Add subgraph execution support

Add -S option to support subgraph execution. This would allow a user
to pick which tasks to stop on.

Example:

fuel2 graph execute -S keystone-db:openstack-controller/1

will start with all keystone-db tasks and end at openstack-controller at
node-1

DocImpact

Change-Id: I42f9caf2e9c18072a2ae0447df2ba3500f687d5e
Closes-bug: 1612616
(cherry picked from commit e41e6511a9)
This commit is contained in:
Vladimir Kuklin 2016-08-09 19:43:20 +03:00 committed by Sergii Golovatiuk
parent 8ac48ac48f
commit b1bc65269c
4 changed files with 98 additions and 9 deletions

View File

@ -186,6 +186,15 @@ class GraphExecute(base.BaseTasksExecuteCommand):
nargs='+',
help='List of deployment tasks to run.'
)
parser.add_argument('-S',
'--subgraphs',
type=str,
nargs='+',
required=False,
help='List of subgraphs to execute'
'Format is: '
'[<start_task>[/<node_ids>]]\
[:<end_task>/[<node_ids>]]')
return parser
def get_options(self, parsed_args):
@ -193,7 +202,7 @@ class GraphExecute(base.BaseTasksExecuteCommand):
'graph_types': parsed_args.graph_types,
'nodes': parsed_args.nodes,
'task_names': parsed_args.task_names,
'subgraphs': parsed_args.subgraphs
}

View File

@ -178,7 +178,8 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=False,
noop_run=False,
force=False,
debug=False
debug=False,
subgraphs=None
)
)
@ -194,7 +195,8 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=True,
noop_run=False,
force=False,
debug=False
debug=False,
subgraphs=None
)
)
@ -210,7 +212,8 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=False,
noop_run=False,
force=True,
debug=False
debug=False,
subgraphs=None
)
)
@ -226,7 +229,8 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=False,
noop_run=False,
force=False,
debug=False
debug=False,
subgraphs=None
)
)
@ -242,7 +246,8 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=False,
noop_run=True,
force=False,
debug=False
debug=False,
subgraphs=None
)
)
@ -258,7 +263,28 @@ class TestGraphActions(test_engine.BaseCLITest):
dry_run=False,
noop_run=False,
force=False,
debug=True
debug=True,
subgraphs=None
)
)
def test_execute_w_dry_run_subgraph(self):
self._test_cmd(
'execute',
'--env 1 --graph-types custom_graph --nodes 1 2 3 '
'--dry-run --subgraphs primary-database/1,3:keystone-db/1-2,5'
' openstack-controller',
dict(
env_id=1,
force=False,
graph_types=['custom_graph'],
nodes=[1, 2, 3],
noop_run=False,
dry_run=True,
subgraphs=['primary-database/1,3:keystone-db/1-2,5',
'openstack-controller'],
task_names=None,
debug=False
)
)

View File

@ -289,8 +289,43 @@ class TestDeploymentGraphFacade(test_api.BaseLibTest):
self.assertItemsEqual(
cluster_graphs + not_this_env_cluster_graphs + release_graphs,
self.client.list(filters=['cluster', 'release'])
self.client.list(filters=['cluster', 'release']))
def test_new_graph_dry_run_subgraph(self):
matcher_post = self.m_request.post(
'/api/v1/graphs/execute/',
json=utils.get_fake_task(cluster=370))
# this is required to form running task info
self.m_request.get(
'/api/v1/nodes/?cluster_id=370',
json={}
)
self.client.execute(
env_id=1,
nodes=[1, 2, 3],
graph_types=["custom_graph"],
dry_run=True,
subgraphs=['primary-database/1,3:keystone-db/1-2,5',
'openstack-controller']
)
self.assertTrue(matcher_post.called)
expected_body = {'cluster': 1,
'dry_run': True,
'graphs':
[{
'nodes': [1, 2, 3], 'type': 'custom_graph',
'tasks': ['rsync_core_puppet']},
{
'nodes': [1, 2, 3],
'type': 'another_custom_graph',
'tasks': ['rsync_core_puppet']}],
'subgraphs': [
{'start': ['primary-database/1,3'],
'end': ['keystone-db/1-2,5']},
{'start': ['openstack-controller'],
'end': [None]}]
}
self.assertItemsEqual(matcher_post.last_request.json(), expected_body)
def test_graphs_download_all(self):
matcher_get = self.m_request.get(

View File

@ -13,6 +13,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
import six
from fuelclient.cli import error
@ -88,7 +89,7 @@ class GraphClient(base_v1.BaseV1Client):
method(data, related_model, related_id, graph_type)
def execute(self, env_id, nodes=None, graph_types=None, task_names=None,
**kwargs):
subgraphs=None, **kwargs):
request_data = {'cluster': env_id}
def map_args_to_graph_types(graph):
@ -100,12 +101,30 @@ class GraphClient(base_v1.BaseV1Client):
result['tasks'] = task_names
return result
def munge_subgraphs(subgraph):
regexp = re.compile("^([\w\-,]+(?:\/(?:(?:\d+(?:,|-)?)+))?)"
"?(:[\w\-,]+(?:\/(?:(?:\d+(?:,|-)?)+))?)?$")
result = regexp.match(subgraph)
start_vertex = None
end_vertex = None
if result:
if result.group(1):
start_vertex = result.group(1)
if result.group(2):
end_vertex = result.group(2)[1:]
return {'start': [start_vertex], 'end': [end_vertex]}
if graph_types:
request_data['graphs'] = list(six.moves.map(
map_args_to_graph_types, graph_types
))
if subgraphs:
request_data['subgraphs'] = list(
six.moves.map(lambda s: munge_subgraphs(s), subgraphs))
request_data.update(kwargs)
deploy_data = self.connection.post_request(
self.cluster_deploy_api_path,
request_data