Deploy handlers validation is now custom graph aware

TaskDeployGraph and DeploySelectedNodesWithTasks handlers
now validating data using deployment graph type

Change-Id: I0f7b19a9695bd2ed608d2bf3b6dd28ae91bc86e2
Partial-Bug: #1567504
This commit is contained in:
Ilya Kutukov 2016-04-12 16:29:02 +03:00
parent 513a055ab7
commit e1882de71c
5 changed files with 159 additions and 10 deletions

View File

@ -314,8 +314,12 @@ class DeploySelectedNodesWithTasks(BaseDeploySelectedNodes):
cluster = self.get_object_or_404(objects.Cluster, cluster_id)
data = self.checked_data(
self.validator.validate_deployment,
cluster=cluster)
return self.handle_task(cluster, deployment_tasks=data)
cluster=cluster,
graph_type=self.get_graph_type())
return self.handle_task(
cluster,
deployment_tasks=data,
graph_type=self.get_graph_type())
class TaskDeployGraph(BaseHandler):
@ -344,7 +348,8 @@ class TaskDeployGraph(BaseHandler):
tasks = self.checked_data(
self.validator.validate,
data=tasks,
cluster=cluster)
cluster=cluster,
graph_type=graph_type)
logger.debug('Tasks used in dot graph %s', tasks)
if parents_for:

View File

@ -423,16 +423,18 @@ class NodeDeploymentValidator(TaskDeploymentValidator,
DeploySelectedNodesValidator):
@classmethod
def validate_deployment(cls, data, cluster):
def validate_deployment(cls, data, cluster, graph_type):
"""Used to validate attributes used for validate_deployment_attributes
:param data: raw json data, usually web.data()
:param cluster: cluster instance
:param graph_type: deployment graph type
:returns: loaded json or empty array
"""
data = cls.validate_json(data)
if data:
cls.validate_tasks(data, cluster)
cls.validate_tasks(data, cluster, graph_type)
else:
raise errors.InvalidData('Tasks list must be specified.')

View File

@ -34,16 +34,22 @@ class GraphSolverTasksValidator(BasicValidator):
class TaskDeploymentValidator(BasicValidator):
@classmethod
def validate_tasks(cls, tasks, cluster):
"""Check that passed tasks are present in deployment graph
def validate_tasks(cls, tasks, cluster, graph_type):
"""Check that passed tasks are present in deployment graph.
:param tasks: list of tasks
:type tasks: list[dict]
:param cluster: Cluster DB object
:type cluster: models.Cluster
:param graph_type: Deployment graph type
:type graph_type: basestring
:returns: list of tasks
:rtype: list[dict]
"""
cls.validate_schema(tasks, base_types.STRINGS_ARRAY)
deployment_tasks = objects.Cluster.get_deployment_tasks(cluster)
deployment_tasks = objects.Cluster.get_deployment_tasks(
cluster, graph_type)
graph = orchestrator_graph.GraphSolver()
graph.add_tasks(deployment_tasks)
@ -73,15 +79,21 @@ class TaskDeploymentValidator(BasicValidator):
class GraphSolverVisualizationValidator(TaskDeploymentValidator):
@classmethod
def validate(cls, data, cluster):
def validate(cls, data, cluster, graph_type):
"""Check that passed tasks are present in deployment graph
:param data: list of tasks in string representation.
Example: "hiera,controller"
:type data: basestring
:param cluster: Cluster DB object
:type cluster: models.Cluster
:param graph_type: Deployment graph type
:type graph_type: basestring
:returns: list of tasks
:rtype: list[dict]
"""
tasks = list(set(data.split(',')))
return cls.validate_tasks(tasks, cluster)
return cls.validate_tasks(tasks, cluster, graph_type)
@classmethod
def validate_task_presence(cls, task, graph):

View File

@ -761,6 +761,74 @@ class TestTaskDeployGraph(BaseGraphTasksTests):
self.assertIn('Task types nonexistent do not exist', resp.body)
class TestCustomTaskDeployGraph(BaseGraphTasksTests):
content_type = 'text/vnd.graphviz'
def test_with_custom_graph(self):
self.env.create()
cluster = self.env.clusters[-1]
objects.DeploymentGraph.create_for_model(
{
'tasks': [
{'id': 'pre_deployment', 'type': 'stage'},
{'id': 'deploy', 'type': 'stage'},
{'id': 'post_deployment', 'type': 'stage'},
{'id': 'pre-A', 'required_for': ['pre_deployment'],
'type': 'puppet'},
{'id': 'pre-B', 'required_for': ['pre_deployment'],
'type': 'puppet', 'requires': ['pre-A']},
{'id': 'pre-C', 'required_for': ['pre_deployment'],
'type': 'puppet', 'requires': ['pre-A', 'pre-D']},
{'id': 'pre-D', 'required_for': ['pre_deployment'],
'type': 'puppet'},
]
},
cluster,
'custom-graph'
)
resp = self.app.get(
reverse('TaskDeployGraph', kwargs={
'cluster_id': cluster.id,
'graph_type': 'custom-graph'
}) + '?graph_type=custom-graph',
expect_errors=True
)
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.content_type, self.content_type)
self.assertIn('"pre-A" -> pre_deployment', resp.body)
self.assertIn('"pre-A" -> "pre-B"', resp.body)
self.assertIn('"pre-A" -> "pre-C"', resp.body)
def test_with_custom_graph_validator_fail(self):
self.env.create()
cluster = self.env.clusters[-1]
objects.DeploymentGraph.create_for_model(
{
'tasks': []
},
cluster,
'custom-graph'
)
resp = self.app.get(
reverse('TaskDeployGraph', kwargs={
'cluster_id': cluster.id,
'graph_type': 'custom-graph'
}) + '?graph_type=custom-graph&parents_for=upload_nodes_info',
expect_errors=True
)
self.assertEqual(resp.status_code, 400)
self.assertIn(
'Task upload_nodes_info is not present in graph',
resp.body)
class TestTaskDeployCustomGraph(BaseGraphTasksTests):
content_type = 'text/vnd.graphviz'

View File

@ -263,6 +263,68 @@ class TestSelectedNodesAction(BaseSelectedNodesTest):
self.check_deployment_call_made([nodes_uids[0]], mcast)
@patch('nailgun.task.task.rpc.cast')
def test_start_sel_nodes_deployment_w_custom_graph(self, mcast):
controller_nodes = [
n for n in self.cluster.nodes
if "controller" in n.roles
]
objects.DeploymentGraph.create_for_model(
{'tasks': [
{
'id': 'custom-task',
'type': 'puppet',
'roles': '*',
'version': '2.0.0',
'requires': ['pre_deployment_start']
}
]}, self.cluster, 'custom-graph')
self.emulate_nodes_provisioning(controller_nodes)
nodes_uids = [n.uid for n in controller_nodes]
controller_to_deploy = nodes_uids[0]
deploy_action_url = self.make_action_url(
"DeploySelectedNodesWithTasks",
[controller_to_deploy]
) + '&graph_type=custom-graph'
self.send_put(deploy_action_url, ['custom-task'])
executed_task_ids = [
t['id'] for t in
mcast.call_args[0][1]['args']['tasks_graph'][controller_to_deploy]
]
self.check_deployment_call_made([controller_to_deploy], mcast)
self.assertItemsEqual(['custom-task'], executed_task_ids)
@patch('nailgun.task.task.rpc.cast')
def test_validator_fail_on_deployment_w_custom_graph(self, mcast):
objects.DeploymentGraph.create_for_model(
{'tasks': [
{
'id': 'custom-task',
'type': 'puppet',
}
]}, self.cluster, 'custom-graph')
deploy_action_url = self.make_action_url(
"DeploySelectedNodesWithTasks",
[]
) + '&graph_type=custom-graph'
response = self.send_put(
deploy_action_url,
['upload_nodes_info'] # this task exists in default graph
)
self.assertEqual(response.status_code, 400)
self.assertEqual(
response.json_body,
{
"message": "Tasks upload_nodes_info are not present "
"in deployment graph",
"errors": []
}
)
@fake_tasks(fake_rpc=False, mock_rpc=False)
@patch('nailgun.task.task.rpc.cast')
def test_deployment_of_node_is_forbidden(self, mcast):