def create(cls, data): """Create Release instance with specified parameters in DB. :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) # process graphs graphs = {} graphs_list = data.pop('graphs', []) for graph in graphs_list: graphs[graph.pop('type')] = graph deployment_tasks = data.pop("deployment_tasks", []) if not graphs.get(consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE): graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} release_obj = super(Release, cls).create(data) for graph_type, graph_data in six.iteritems(graphs): DeploymentGraph.create_for_model( graph_data, release_obj, graph_type) cls.create_tags(release_obj) return release_obj
def update(cls, instance, data): # Plugin name can't be changed. Plugins sync operation uses # name for searching plugin data on the file system. new_name = data.get('name') if new_name is not None and instance.name != new_name: raise errors.InvalidData( "Plugin can't be renamed. Trying to change name " "of the plugin {0} to {1}".format(instance.name, new_name)) graphs = {} data_graphs = data.pop("graphs", []) for graph in data_graphs: graphs[graph.pop('type')] = graph data.pop("deployment_tasks", []) # could not be updated # We must save tags info in the roles_metadata on the update data = cls._process_tags(data) super(Plugin, cls).update(instance, data) for graph_type, graph_data in six.iteritems(graphs): existing_graph = DeploymentGraph.get_for_model( instance, graph_type=graph_type) if existing_graph: DeploymentGraph.update(existing_graph, graph_data) else: DeploymentGraph.create_for_model(graph_data, instance, graph_type)
def create(cls, data): """Create Release instance with specified parameters in DB. :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) # process graphs graphs = {} graphs_list = data.pop('graphs', []) for graph in graphs_list: graphs[graph.pop('type')] = graph deployment_tasks = data.pop("deployment_tasks", []) if not graphs.get(consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE): graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} release_obj = super(Release, cls).create(data) for graph_type, graph_data in six.iteritems(graphs): DeploymentGraph.create_for_model(graph_data, release_obj, graph_type) return release_obj
def test_graphs_list_filtered_release_and_plugin(self): expected_list = [{ 'id': DeploymentGraph.get_for_model(self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': DeploymentGraph.get_for_model(self.plugin, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.plugin.id, 'model': 'plugin', 'type': 'default' }], }] response = self.app.get( reverse('DeploymentGraphCollectionHandler', kwargs={}) + '?releases_ids={}&plugins_ids={}'.format(self.cluster.release.id, self.plugin.id), headers=self.default_headers).json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response)
def delete(cls, instance): """Delete release. :param instance: Release model instance :type instance: models.Release """ DeploymentGraph.delete_for_parent(instance) super(Release, cls).delete(instance)
def test_get_deployment_tasks(self): dg = DeploymentGraph.get_for_model(self.plugin_adapter.plugin) DeploymentGraph.update( dg, {'tasks': self.env.get_default_plugin_deployment_tasks()}) depl_task = self.plugin_adapter.get_deployment_tasks()[0] self.assertEqual(depl_task['parameters'].get('cwd'), self.plugin_adapter.slaves_scripts_path)
def delete(cls, instance): """Delete plugin. :param instance: Plugin model instance :type instance: models.Plugin """ DeploymentGraph.delete_for_parent(instance) super(Plugin, cls).delete(instance)
def test_get_deployment_tasks_params_not_changed(self): expected = 'path/to/some/dir' dg = DeploymentGraph.get_for_model(self.plugin_adapter.plugin) DeploymentGraph.update( dg, { 'tasks': self.env.get_default_plugin_deployment_tasks( parameters={'cwd': expected}) }) depl_task = self.plugin_adapter.get_deployment_tasks()[0] self.assertEqual(depl_task['parameters'].get('cwd'), expected)
def test_graphs_list_filtered_cluster(self): expected_list = [ { 'id': DeploymentGraph.get_for_model( self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': DeploymentGraph.get_for_model(self.cluster).id, 'name': None, 'relations': [{ 'model_id': self.cluster.id, 'model': 'cluster', 'type': 'default' }] }, { 'id': DeploymentGraph.get_for_model( self.cluster, graph_type='custom-graph').id, 'name': 'custom-graph-name', 'relations': [{ 'model_id': self.cluster.id, 'model': 'cluster', 'type': 'custom-graph' }] }, { 'id': DeploymentGraph.get_for_model(self.plugin).id, 'name': None, 'relations': [{ 'model_id': self.plugin.id, 'model': 'plugin', 'type': 'default' }], } ] response = self.app.get( reverse( 'DeploymentGraphCollectionHandler', kwargs={} ) + '?clusters_ids={}&fetch_related=1'.format(self.cluster.id), headers=self.default_headers ).json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response)
def test_get_deployment_tasks(self): dg = DeploymentGraph.get_for_model(self.plugin_adapter.plugin) DeploymentGraph.update( dg, { 'tasks': self.env.get_default_plugin_deployment_tasks() } ) depl_task = self.plugin_adapter.get_deployment_tasks()[0] self.assertEqual(depl_task['parameters'].get('cwd'), self.plugin_adapter.slaves_scripts_path)
def test_get_deployment_tasks_params_not_changed(self): expected = 'path/to/some/dir' dg = DeploymentGraph.get_for_model(self.plugin_adapter.plugin) DeploymentGraph.update( dg, { 'tasks': self.env.get_default_plugin_deployment_tasks( parameters={'cwd': expected}) } ) depl_task = self.plugin_adapter.get_deployment_tasks()[0] self.assertEqual(depl_task['parameters'].get('cwd'), expected)
def create(cls, data): # accidental because i've seen this way of tasks creation only in tests deployment_tasks = data.pop('deployment_tasks', []) new_plugin = super(Plugin, cls).create(data) # create default graph in any case DeploymentGraph.create_for_model( {'tasks': deployment_tasks}, new_plugin) plugin_adapter = wrap_plugin(new_plugin) cls.update(new_plugin, plugin_adapter.get_metadata()) ClusterPlugin.add_compatible_clusters(new_plugin) return new_plugin
def create(cls, data): # accidental because i've seen this way of tasks creation only in tests deployment_tasks = data.pop('deployment_tasks', []) new_plugin = super(Plugin, cls).create(data) # create default graph in any case DeploymentGraph.create_for_model({'tasks': deployment_tasks}, new_plugin) plugin_adapter = wrap_plugin(new_plugin) cls.update(new_plugin, plugin_adapter.get_metadata()) ClusterPlugins.add_compatible_clusters(new_plugin) return new_plugin
def create(cls, data): """Create Release instance with specified parameters in DB. :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) deployment_tasks = data.pop("deployment_tasks", []) release_obj = super(Release, cls).create(data) DeploymentGraph.create_for_model({'tasks': deployment_tasks}, release_obj) return release_obj
def create(cls, data): """Create Release instance with specified parameters in DB. :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) deployment_tasks = data.pop("deployment_tasks", []) release_obj = super(Release, cls).create(data) DeploymentGraph.create_for_model( {'tasks': deployment_tasks}, release_obj) return release_obj
def setUp(self): super(TestGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) plugin_data = { 'releases': [ { 'repository_path': 'repositories/ubuntu', 'version': self.cluster.release.version, 'os': self.cluster.release.operating_system.lower(), 'mode': [self.cluster.mode], } ], 'cluster': self.cluster, 'enabled': True, } self.plugin = self.env.create_plugin(**plugin_data) self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': [{ 'id': 'custom-task', 'type': 'puppet' }] }, self.cluster, graph_type='custom-graph' ) self.env.db().commit()
def setUp(self): super(TestGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) plugin_data = { 'releases': [{ 'repository_path': 'repositories/ubuntu', 'version': self.cluster.release.version, 'os': self.cluster.release.operating_system.lower(), 'mode': [self.cluster.mode], }], 'cluster': self.cluster, 'enabled': True, } self.plugin = self.env.create_plugin(**plugin_data) self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': [{ 'id': 'custom-task', 'type': 'puppet' }] }, self.cluster, graph_type='custom-graph') self.env.db().commit()
def update(cls, instance, data): graphs = {} data_graphs = data.pop("graphs", []) for graph in data_graphs: graphs[graph.pop('type')] = graph data.pop("deployment_tasks", []) # could not be updated super(Plugin, cls).update(instance, data) for graph_type, graph_data in six.iteritems(graphs): existing_graph = DeploymentGraph.get_for_model( instance, graph_type=graph_type) if existing_graph: DeploymentGraph.update(existing_graph, graph_data) else: DeploymentGraph.create_for_model( graph_data, instance, graph_type)
def test_graphs_list_request(self): default_graph = DeploymentGraph.get_for_model(self.cluster) expected_list = [ { 'id': DeploymentGraph.get_for_model( self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': self.custom_graph.id, 'name': 'custom-graph-name', 'relations': [{ 'type': 'custom-graph', 'model': 'cluster', 'model_id': self.cluster.id }] }, { 'id': default_graph.id, 'relations': [ { 'model': 'cluster', 'model_id': self.cluster.id, 'type': 'default' } ], 'name': None } ] resp = self.app.get( reverse( 'DeploymentGraphCollectionHandler', kwargs={} ), headers=self.default_headers ) response = resp.json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response)
def update(cls, instance, data): graphs = {} data_graphs = data.pop("graphs", []) for graph in data_graphs: graphs[graph.pop('type')] = graph data.pop("deployment_tasks", []) # could not be updated super(Plugin, cls).update(instance, data) for graph_type, graph_data in six.iteritems(graphs): existing_graph = DeploymentGraph.get_for_model( instance, graph_type=graph_type) if existing_graph: DeploymentGraph.update(existing_graph, graph_data) else: DeploymentGraph.create_for_model(graph_data, instance, graph_type)
def update(cls, instance, data): """Update existing Release instance with specified parameters. :param instance: Release instance :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) deployment_tasks = data.pop("deployment_tasks", None) release_obj = super(Release, cls).update(instance, data) if deployment_tasks: deployment_graph_instance = DeploymentGraph.get_for_model(instance) DeploymentGraph.update(deployment_graph_instance, {'tasks': deployment_tasks}) return release_obj
def test_linked_graphs_list_handler(self): for related_class, ref_graph in six.iteritems(self.custom_graphs): resp = self.app.get(reverse( '{0}DeploymentGraphCollectionHandler'.format(related_class), kwargs={ 'obj_id': ref_graph['model'].id, }), headers=self.default_headers, expect_errors=True) default_graph = DeploymentGraph.get_for_model(ref_graph['model']) self.assertEqual(200, resp.status_code) self.assertItemsEqual([{ 'id': ref_graph['graphs'][0].id, 'name': 'custom-graph-name1', 'tasks': [{ 'id': 'custom-task1', 'task_name': 'custom-task1', 'type': 'puppet', 'version': '1.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph1' }], }, { 'id': ref_graph['graphs'][1].id, 'name': 'custom-graph-name2', 'tasks': [{ 'id': 'custom-task2', 'task_name': 'custom-task2', 'type': 'puppet', 'version': '1.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph2' }], }, { 'tasks': [], 'id': default_graph.id, 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'default' }], 'name': None }], resp.json_body)
def test_graphs_list_request(self): default_graph = DeploymentGraph.get_for_model(self.cluster) expected_list = [{ 'id': DeploymentGraph.get_for_model(self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': self.custom_graph.id, 'name': 'custom-graph-name', 'relations': [{ 'type': 'custom-graph', 'model': 'cluster', 'model_id': self.cluster.id }] }, { 'id': default_graph.id, 'relations': [{ 'model': 'cluster', 'model_id': self.cluster.id, 'type': 'default' }], 'name': None }] resp = self.app.get(reverse('DeploymentGraphCollectionHandler', kwargs={}), headers=self.default_headers) response = resp.json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response)
def create(cls, data): """Create plugin. WARNING: don't pass keys with none to non nullable fields. :param data: data :type data: dict :return: plugin instance :rtype: models.Plugin """ graphs = {} for graph in data.pop("graphs", []): graphs[graph.pop('type')] = graph deployment_tasks = data.pop("deployment_tasks", []) data['releases'] = [ r for r in data.pop("releases", []) if not r.get('is_release', False) ] plugin_obj = super(Plugin, cls).create(data) if not graphs.get(consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE): graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} for graph_type, graph_data in six.iteritems(graphs): DeploymentGraph.create_for_model(graph_data, plugin_obj, graph_type) plugin_adapter = plugins.wrap_plugin(plugin_obj) # todo(ikutukov): this update is a smell from the current plugins # installation schema. Remove it. plugin_meta = cls._process_tags(plugin_adapter.get_metadata()) cls.update(plugin_obj, plugin_meta) ClusterPlugin.add_compatible_clusters(plugin_obj) return plugin_obj
def create(cls, data): """Create plugin. WARNING: don't pass keys with none to non nullable fields. :param data: data :type data: dict :return: plugin instance :rtype: models.Plugin """ graphs = {} for graph in data.pop("graphs", []): graphs[graph.pop('type')] = graph deployment_tasks = data.pop("deployment_tasks", []) data['releases'] = [ r for r in data.pop("releases", []) if not r.get('is_release', False) ] plugin_obj = super(Plugin, cls).create(data) if not graphs.get(consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE): graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} for graph_type, graph_data in six.iteritems(graphs): DeploymentGraph.create_for_model( graph_data, plugin_obj, graph_type) plugin_adapter = plugins.wrap_plugin(plugin_obj) # todo(ikutukov): this update is a smell from the current plugins # installation schema. Remove it. cls.update(plugin_obj, plugin_adapter.get_metadata()) ClusterPlugin.add_compatible_clusters(plugin_obj) return plugin_obj
def update(cls, instance, data): """Update existing Release instance with specified parameters. :param instance: Release instance :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) graphs = data.pop("graphs", {}) deployment_tasks = data.pop("deployment_tasks", []) existing_default_graph = DeploymentGraph.get_for_model( instance, consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE) if (existing_default_graph and len(deployment_tasks)) \ or not existing_default_graph: graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} release_obj = super(Release, cls).update(instance, data) for graph_type, graph_data in six.iteritems(graphs): g = DeploymentGraph.get_for_model(instance, graph_type) if g: DeploymentGraph.update(g, graph_data) else: DeploymentGraph.create_for_model( graph_data, instance, graph_type) return release_obj
def setUp(self): super(TestGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': [{ 'id': 'custom-task', 'type': 'puppet' }] }, self.cluster, graph_type='custom-graph')
def create(cls, data): graphs = data.pop("graphs", {}) deployment_tasks = data.pop("deployment_tasks", []) if not graphs.get(consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE): graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} plugin_obj = super(Plugin, cls).create(data) for graph_type, graph_data in six.iteritems(graphs): DeploymentGraph.create_for_model( graph_data, plugin_obj, graph_type) plugin_adapter = plugins.wrap_plugin(plugin_obj) # todo(ikutukov): this update is a smell from the current plugins # todo: installation schema. Remove it. cls.update(plugin_obj, plugin_adapter.get_metadata()) ClusterPlugin.add_compatible_clusters(plugin_obj) return plugin_obj
def test_graph_delete(self): graph_id = self.custom_graph.id resp = self.app.delete(reverse('DeploymentGraphHandler', kwargs={'obj_id': graph_id}), headers=self.default_headers, expect_errors=True) self.assertEqual(204, resp.status_code) graph = DeploymentGraph.get_by_uid(graph_id) self.assertIsNone(graph) resp = self.app.get(reverse('DeploymentGraphHandler', kwargs={'obj_id': graph_id}), headers=self.default_headers, expect_errors=True) self.assertEqual(404, resp.status_code)
def setUp(self): super(TestGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': [{ 'id': 'custom-task', 'type': 'puppet' }] }, self.cluster, graph_type='custom-graph' )
def test_existing_graph_update(self): for related_class, ref_graph in six.iteritems(self.custom_graphs): resp = self.app.put( reverse( '{0}DeploymentGraphHandler'.format(related_class), kwargs={ 'obj_id': ref_graph['model'].id, 'graph_type': 'custom-graph1' } ), jsonutils.dumps({ 'name': 'updated-graph-name', 'tasks': [{ 'id': 'test-task2', 'type': 'puppet', 'version': '2.0.0' }] }), headers=self.default_headers ) graph_id = DeploymentGraph.get_for_model( ref_graph['model'], 'custom-graph1').id self.assertEqual(200, resp.status_code) self.assertEqual( { 'id': graph_id, 'name': 'updated-graph-name', 'tasks': [{ 'id': 'test-task2', 'type': 'puppet', 'task_name': 'test-task2', 'version': '2.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph1' }] }, resp.json_body )
def setUp(self): super(TestCustomGraphAction, self).setUp() self.custom_tasks = [{ 'id': 'first-custom-task', 'type': 'stage', 'requires': ['pre_deployment_end'] }, { 'id': 'second-custom-task', 'type': 'stage', 'requires': ['deploy_start'] }] self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': self.custom_tasks }, self.cluster, graph_type='custom-graph') self.env.db().commit()
def get_deployment_graph(cls, instance, graph_type=None): """Get deployment graph based on release version. :param instance: Release instance :type instance: models.Release :param graph_type: deployment graph type :type graph_type: basestring|None :returns: list of deployment tasks :rtype: list """ if graph_type is None: graph_type = consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE env_version = instance.environment_version deployment_graph = DeploymentGraph.get_for_model(instance, graph_type) if deployment_graph: deployment_tasks = DeploymentGraph.get_tasks(deployment_graph) else: # deployment tasks list should always be returned deployment_tasks = [] if graph_type == consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE and \ not deployment_tasks: # upload default legacy graphs if env_version.startswith('5.0'): deployment_tasks = yaml.load( graph_configuration.DEPLOYMENT_50) elif env_version.startswith('5.1') \ or env_version.startswith('6.0'): deployment_tasks = yaml.load( graph_configuration.DEPLOYMENT_51_60) if deployment_graph: if deployment_tasks: DeploymentGraph.update( deployment_graph, {'tasks': deployment_tasks}) else: # create graph anyway deployment_graph = DeploymentGraph.create_for_model( {'tasks': deployment_tasks}, instance) if deployment_graph: metadata = DeploymentGraph.get_metadata(deployment_graph) else: metadata = {} metadata['tasks'] = deployment_tasks return metadata
def test_existing_graph_update(self): for related_class, ref_graph in six.iteritems(self.custom_graphs): resp = self.app.put(reverse( '{0}DeploymentGraphHandler'.format(related_class), kwargs={ 'obj_id': ref_graph['model'].id, 'graph_type': 'custom-graph1' }), jsonutils.dumps({ 'name': 'updated-graph-name', 'tasks': [{ 'id': 'test-task2', 'type': 'puppet', 'version': '2.0.0' }] }), headers=self.default_headers) graph_id = DeploymentGraph.get_for_model(ref_graph['model'], 'custom-graph1').id self.assertEqual(200, resp.status_code) self.assertEqual( { 'id': graph_id, 'name': 'updated-graph-name', 'tasks': [{ 'id': 'test-task2', 'type': 'puppet', 'task_name': 'test-task2', 'version': '2.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph1' }] }, resp.json_body)
def get_deployment_graph(cls, instance, graph_type=None): """Get deployment graph based on release version. :param instance: Release instance :type instance: models.Release :param graph_type: deployment graph type :type graph_type: basestring|None :returns: list of deployment tasks :rtype: list """ if graph_type is None: graph_type = consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE env_version = instance.environment_version deployment_graph = DeploymentGraph.get_for_model(instance, graph_type) if deployment_graph: deployment_tasks = DeploymentGraph.get_tasks(deployment_graph) else: # deployment tasks list should always be returned deployment_tasks = [] if graph_type == consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE and \ not deployment_tasks: # upload default legacy graphs if env_version.startswith('5.0'): deployment_tasks = yaml.load(graph_configuration.DEPLOYMENT_50) elif env_version.startswith('5.1') \ or env_version.startswith('6.0'): deployment_tasks = yaml.load( graph_configuration.DEPLOYMENT_51_60) if deployment_graph: if deployment_tasks: DeploymentGraph.update(deployment_graph, {'tasks': deployment_tasks}) else: # create graph anyway deployment_graph = DeploymentGraph.create_for_model( {'tasks': deployment_tasks}, instance) if deployment_graph: metadata = DeploymentGraph.get_metadata(deployment_graph) else: metadata = {} metadata['tasks'] = deployment_tasks return metadata
def test_graph_delete(self): graph_id = self.custom_graph.id resp = self.app.delete( reverse( 'DeploymentGraphHandler', kwargs={'obj_id': graph_id} ), headers=self.default_headers, expect_errors=True ) self.assertEqual(204, resp.status_code) graph = DeploymentGraph.get_by_uid(graph_id) self.assertIsNone(graph) resp = self.app.get( reverse( 'DeploymentGraphHandler', kwargs={'obj_id': graph_id} ), headers=self.default_headers, expect_errors=True ) self.assertEqual(404, resp.status_code)
def setUp(self): super(TestCustomGraphAction, self).setUp() self.custom_tasks = [ { 'id': 'first-custom-task', 'type': 'stage', 'requires': ['pre_deployment_end'] }, { 'id': 'second-custom-task', 'type': 'stage', 'requires': ['deploy_start'] } ] self.custom_graph = DeploymentGraph.create_for_model( { 'name': 'custom-graph-name', 'tasks': self.custom_tasks }, self.cluster, graph_type='custom-graph' ) self.env.db().commit()
def update(cls, instance, data): """Update existing Release instance with specified parameters. :param instance: Release instance :param data: dictionary of key-value pairs as object fields :returns: Release instance """ # in order to be compatible with old API, let's drop input # roles array. since fuel 7.0 we don't use it anymore, and # we don't require it even for old releases. data.pop("roles", None) graphs = {} graphs_list = data.pop('graphs', []) for graph in graphs_list: graphs[graph.pop('type')] = graph deployment_tasks = data.pop("deployment_tasks", []) existing_default_graph = DeploymentGraph.get_for_model( instance, consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE) if (existing_default_graph and len(deployment_tasks)) \ or not existing_default_graph: graphs[consts.DEFAULT_DEPLOYMENT_GRAPH_TYPE] = \ {'tasks': deployment_tasks} release_obj = super(Release, cls).update(instance, data) for graph_type, graph_data in six.iteritems(graphs): g = DeploymentGraph.get_for_model(instance, graph_type) if g: DeploymentGraph.update(g, graph_data) else: DeploymentGraph.create_for_model(graph_data, instance, graph_type) return release_obj
def test_linked_graphs_list_handler(self): for related_class, ref_graph in six.iteritems(self.custom_graphs): resp = self.app.get( reverse( '{0}DeploymentGraphCollectionHandler'.format( related_class), kwargs={ 'obj_id': ref_graph['model'].id, } ), headers=self.default_headers, expect_errors=True ) default_graph = DeploymentGraph.get_for_model(ref_graph['model']) self.assertEqual(200, resp.status_code) self.assertItemsEqual( [ { 'id': ref_graph['graphs'][0].id, 'name': 'custom-graph-name1', 'tasks': [{ 'id': 'custom-task1', 'task_name': 'custom-task1', 'type': 'puppet', 'version': '1.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph1' }], }, { 'id': ref_graph['graphs'][1].id, 'name': 'custom-graph-name2', 'tasks': [{ 'id': 'custom-task2', 'task_name': 'custom-task2', 'type': 'puppet', 'version': '1.0.0' }], 'relations': [{ 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'custom-graph2' }], }, { 'tasks': [], 'id': default_graph.id, 'relations': [ { 'model': related_class.lower(), 'model_id': ref_graph['model'].id, 'type': 'default' } ], 'name': None } ], resp.json_body )
def test_graphs_list_request(self): default_graph = DeploymentGraph.get_for_model(self.cluster) expected_list = [{ 'id': DeploymentGraph.get_for_model(self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': self.custom_graph.id, 'name': 'custom-graph-name', 'relations': [{ 'type': 'custom-graph', 'model': 'cluster', 'model_id': self.cluster.id }] }, { 'id': default_graph.id, 'relations': [{ 'model': 'cluster', 'model_id': self.cluster.id, 'type': 'default' }], 'name': None }, { 'id': DeploymentGraph.get_for_model(self.plugin, graph_type='default').id, 'relations': [{ 'model_id': self.plugin.id, 'model': 'plugin', 'type': 'default' }], 'name': None }] response = self.app.get( reverse('DeploymentGraphCollectionHandler', kwargs={}) + '?fetch_related=1', headers=self.default_headers).json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response) # and check filtered output response_filtered_by_type = self.app.get( reverse('DeploymentGraphCollectionHandler', kwargs={}) + '?fetch_related=1&graph_types=default', headers=self.default_headers).json_body for r in response_filtered_by_type: r.pop('tasks') self.assertItemsEqual((el for el in expected_list if el['relations'][0]['type'] == 'default'), response_filtered_by_type)
def setUp(self): super(TestLinkedGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) plugin_data = { 'releases': [ { 'repository_path': 'repositories/ubuntu', 'version': self.cluster.release.version, 'os': self.cluster.release.operating_system.lower(), 'mode': [self.cluster.mode], } ], 'cluster': self.cluster, 'enabled': True, } self.plugin = self.env.create_plugin(**plugin_data) self.env.db().commit() custom_graph1_data = { 'name': 'custom-graph-name1', 'tasks': [{ 'id': 'custom-task1', 'type': 'puppet' }] } custom_graph2_data = { 'name': 'custom-graph-name2', 'tasks': [{ 'id': 'custom-task2', 'type': 'puppet' }] } # replace default release graph with empty version to avoid # because it's default graph have special content DeploymentGraph.delete( DeploymentGraph.get_for_model(self.cluster.release)) DeploymentGraph.create_for_model({}, self.cluster.release) self.custom_graphs = { 'Cluster': { 'model': self.cluster, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.cluster, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.cluster, graph_type='custom-graph2') ] }, 'Release': { 'model': self.cluster.release, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.cluster.release, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.cluster.release, graph_type='custom-graph2'), ] }, 'Plugin': { 'model': self.plugin, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.plugin, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.plugin, graph_type='custom-graph2') ] } }
def test_graphs_creation(self): metadata_update = { 'name': 'graphs_plugin', 'description': 'testing graphs', 'package_version': '5.0.0', 'graphs': [{ 'type': 'default', 'name': 'default', 'tasks': [{ 'id': 'default', 'type': 'puppet' }] }, { 'type': 'custom', 'name': 'custom', 'tasks': [{ 'id': 'custom', 'type': 'puppet' }] }] } metadata = self.env.get_default_plugin_metadata() metadata.update(metadata_update) plugin = Plugin.create(metadata) def_graph = DeploymentGraph.get_for_model(plugin, graph_type='default') self.assertEqual(def_graph.name, 'default') self.assertEqual(DeploymentGraph.get_tasks(def_graph), [{ 'id': 'default', 'task_name': 'default', 'type': 'puppet', 'version': '1.0.0' }]) custom_graph = DeploymentGraph.get_for_model(plugin, graph_type='custom') self.assertEqual(custom_graph.name, 'custom') self.assertEqual(DeploymentGraph.get_tasks(custom_graph), [{ 'id': 'custom', 'task_name': 'custom', 'type': 'puppet', 'version': '1.0.0' }]) Plugin.update(plugin, metadata) def_graph = DeploymentGraph.get_for_model(plugin, graph_type='default') self.assertEqual(def_graph.name, 'default') self.assertEqual(DeploymentGraph.get_tasks(def_graph), [{ 'id': 'default', 'task_name': 'default', 'type': 'puppet', 'version': '1.0.0' }]) custom_graph = DeploymentGraph.get_for_model(plugin, graph_type='custom') self.assertEqual(custom_graph.name, 'custom') self.assertEqual(DeploymentGraph.get_tasks(custom_graph), [{ 'id': 'custom', 'task_name': 'custom', 'type': 'puppet', 'version': '1.0.0' }])
def setUp(self): super(TestLinkedGraphHandlers, self).setUp() self.cluster = self.env.create_cluster(api=False) plugin_data = { 'releases': [{ 'repository_path': 'repositories/ubuntu', 'version': self.cluster.release.version, 'os': self.cluster.release.operating_system.lower(), 'mode': [self.cluster.mode], }], 'cluster': self.cluster, 'enabled': True, } self.plugin = self.env.create_plugin(**plugin_data) self.env.db().commit() custom_graph1_data = { 'name': 'custom-graph-name1', 'tasks': [{ 'id': 'custom-task1', 'type': 'puppet' }] } custom_graph2_data = { 'name': 'custom-graph-name2', 'tasks': [{ 'id': 'custom-task2', 'type': 'puppet' }] } # replace default release graph with empty version to avoid # because it's default graph have special content DeploymentGraph.delete( DeploymentGraph.get_for_model(self.cluster.release)) DeploymentGraph.create_for_model({}, self.cluster.release) self.custom_graphs = { 'Cluster': { 'model': self.cluster, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.cluster, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.cluster, graph_type='custom-graph2') ] }, 'Release': { 'model': self.cluster.release, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.cluster.release, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.cluster.release, graph_type='custom-graph2'), ] }, 'Plugin': { 'model': self.plugin, 'graphs': [ DeploymentGraph.create_for_model( custom_graph1_data, self.plugin, graph_type='custom-graph1'), DeploymentGraph.create_for_model( custom_graph2_data, self.plugin, graph_type='custom-graph2') ] } }
def test_get_metadata(self): plugin_metadata = self.env.get_default_plugin_metadata() attributes_metadata = self.env.get_default_plugin_env_config() roles_metadata = self.env.get_default_plugin_node_roles_config() tags_metadata = self.env.get_default_plugin_node_tags_config() volumes_metadata = self.env.get_default_plugin_volumes_config() network_roles_metadata = self.env.get_default_network_roles_config() deployment_tasks = self.env.get_default_plugin_deployment_tasks() tasks = self.env.get_default_plugin_tasks() components_metadata = self.env.get_default_components() nic_attributes_metadata = self.env.get_default_plugin_nic_config() bond_attributes_metadata = self.env.get_default_plugin_bond_config() node_attributes_metadata = self.env.get_default_plugin_node_config() plugin_metadata.update({ 'attributes_metadata': attributes_metadata, 'roles_metadata': roles_metadata, 'tags_metadata': tags_metadata, 'volumes_metadata': volumes_metadata, 'network_roles_metadata': network_roles_metadata, 'deployment_tasks': deployment_tasks, 'tasks': tasks, 'components_metadata': components_metadata, 'nic_attributes_metadata': nic_attributes_metadata, 'bond_attributes_metadata': bond_attributes_metadata, 'node_attributes_metadata': node_attributes_metadata, 'graphs': [{ 'type': 'custom', 'name': 'custom', 'tasks': [{ 'id': 'task{}'.format(n), 'type': 'puppet' } for n in range(2)] }] }) with mock.patch.object(self.plugin_adapter, 'loader') as loader: loader.load.return_value = (plugin_metadata, ReportNode()) Plugin.update(self.plugin, self.plugin_adapter.get_metadata()) for key, val in six.iteritems({ k: v for (k, v) in six.iteritems(plugin_metadata) if k not in ('deployment_tasks', 'graphs') }): self.assertEqual(getattr(self.plugin, key), val) self.assertEqual(self.plugin.attributes_metadata, attributes_metadata['attributes']) self.assertEqual(self.plugin.roles_metadata, roles_metadata) self.assertEqual(self.plugin.tags_metadata, tags_metadata) self.assertEqual(self.plugin.volumes_metadata, volumes_metadata) self.assertEqual(self.plugin.tasks, tasks) self.assertEqual(self.plugin.components_metadata, components_metadata) self.assertEqual(self.plugin.nic_attributes_metadata, nic_attributes_metadata) self.assertEqual(self.plugin.bond_attributes_metadata, bond_attributes_metadata) self.assertEqual(self.plugin.node_attributes_metadata, node_attributes_metadata) # check custom graph dg = DeploymentGraph.get_for_model(self.plugin, graph_type='custom') self.assertEqual(dg.name, 'custom') self.assertItemsEqual(DeploymentGraph.get_tasks(dg), [{ 'id': 'task{}'.format(i), 'task_name': 'task{}'.format(i), 'type': 'puppet', 'version': '1.0.0' } for i in range(2)]) # deployment tasks returning all non-defined fields, so check # should differ from JSON-stored fields plugin_tasks = self.env.get_default_plugin_deployment_tasks() self.assertGreater(len(plugin_tasks), 0) for k, v in six.iteritems(plugin_tasks[0]): # this field is updated by plugin adapter if k is 'parameters': v.update({'cwd': '/etc/fuel/plugins/testing_plugin-0.1/'}) self.assertEqual( self.plugin_adapter.get_deployment_tasks()[0][k], v)
def test_get_metadata(self): plugin_metadata = self.env.get_default_plugin_metadata() attributes_metadata = self.env.get_default_plugin_env_config() roles_metadata = self.env.get_default_plugin_node_roles_config() tags_metadata = self.env.get_default_plugin_node_tags_config() volumes_metadata = self.env.get_default_plugin_volumes_config() network_roles_metadata = self.env.get_default_network_roles_config() deployment_tasks = self.env.get_default_plugin_deployment_tasks() tasks = self.env.get_default_plugin_tasks() components_metadata = self.env.get_default_components() nic_attributes_metadata = self.env.get_default_plugin_nic_config() bond_attributes_metadata = self.env.get_default_plugin_bond_config() node_attributes_metadata = self.env.get_default_plugin_node_config() plugin_metadata.update({ 'attributes_metadata': attributes_metadata, 'roles_metadata': roles_metadata, 'tags_metadata': tags_metadata, 'volumes_metadata': volumes_metadata, 'network_roles_metadata': network_roles_metadata, 'deployment_tasks': deployment_tasks, 'tasks': tasks, 'components_metadata': components_metadata, 'nic_attributes_metadata': nic_attributes_metadata, 'bond_attributes_metadata': bond_attributes_metadata, 'node_attributes_metadata': node_attributes_metadata, 'graphs': [{ 'type': 'custom', 'name': 'custom', 'tasks': [ {'id': 'task{}'.format(n), 'type': 'puppet'} for n in range(2) ] }] }) with mock.patch.object( self.plugin_adapter, 'loader') as loader: loader.load.return_value = (plugin_metadata, ReportNode()) Plugin.update(self.plugin, self.plugin_adapter.get_metadata()) for key, val in six.iteritems( { k: v for (k, v) in six.iteritems(plugin_metadata) if k not in ('deployment_tasks', 'graphs') } ): self.assertEqual( getattr(self.plugin, key), val) self.assertEqual( self.plugin.attributes_metadata, attributes_metadata['attributes']) self.assertEqual( self.plugin.roles_metadata, roles_metadata) self.assertEqual( self.plugin.tags_metadata, tags_metadata) self.assertEqual( self.plugin.volumes_metadata, volumes_metadata) self.assertEqual( self.plugin.tasks, tasks) self.assertEqual( self.plugin.components_metadata, components_metadata) self.assertEqual( self.plugin.nic_attributes_metadata, nic_attributes_metadata) self.assertEqual( self.plugin.bond_attributes_metadata, bond_attributes_metadata) self.assertEqual( self.plugin.node_attributes_metadata, node_attributes_metadata) # check custom graph dg = DeploymentGraph.get_for_model( self.plugin, graph_type='custom' ) self.assertEqual(dg.name, 'custom') self.assertItemsEqual( DeploymentGraph.get_tasks(dg), [ { 'id': 'task{}'.format(i), 'task_name': 'task{}'.format(i), 'type': 'puppet', 'version': '1.0.0' } for i in range(2) ] ) # deployment tasks returning all non-defined fields, so check # should differ from JSON-stored fields plugin_tasks = self.env.get_default_plugin_deployment_tasks() self.assertGreater(len(plugin_tasks), 0) for k, v in six.iteritems(plugin_tasks[0]): # this field is updated by plugin adapter if k is 'parameters': v.update({ 'cwd': '/etc/fuel/plugins/testing_plugin-0.1/' }) self.assertEqual( self.plugin_adapter.get_deployment_tasks()[0][k], v)
def test_graphs_creation(self): metadata_update = { 'name': 'graphs_plugin', 'description': 'testing graphs', 'package_version': '5.0.0', 'graphs': [ { 'type': 'default', 'name': 'default', 'tasks': [ {'id': 'default', 'type': 'puppet'} ] }, { 'type': 'custom', 'name': 'custom', 'tasks': [ {'id': 'custom', 'type': 'puppet'} ] } ]} metadata = self.env.get_default_plugin_metadata() metadata.update(metadata_update) plugin = Plugin.create(metadata) def_graph = DeploymentGraph.get_for_model( plugin, graph_type='default' ) self.assertEqual(def_graph.name, 'default') self.assertEqual( DeploymentGraph.get_tasks(def_graph), [ { 'id': 'default', 'task_name': 'default', 'type': 'puppet', 'version': '1.0.0' } ] ) custom_graph = DeploymentGraph.get_for_model( plugin, graph_type='custom' ) self.assertEqual(custom_graph.name, 'custom') self.assertEqual( DeploymentGraph.get_tasks(custom_graph), [ { 'id': 'custom', 'task_name': 'custom', 'type': 'puppet', 'version': '1.0.0' } ] ) Plugin.update(plugin, metadata) def_graph = DeploymentGraph.get_for_model( plugin, graph_type='default' ) self.assertEqual(def_graph.name, 'default') self.assertEqual( DeploymentGraph.get_tasks(def_graph), [ { 'id': 'default', 'task_name': 'default', 'type': 'puppet', 'version': '1.0.0' } ] ) custom_graph = DeploymentGraph.get_for_model( plugin, graph_type='custom' ) self.assertEqual(custom_graph.name, 'custom') self.assertEqual( DeploymentGraph.get_tasks(custom_graph), [ { 'id': 'custom', 'task_name': 'custom', 'type': 'puppet', 'version': '1.0.0' } ] )
def test_graphs_list_request(self): default_graph = DeploymentGraph.get_for_model(self.cluster) expected_list = [ { 'id': DeploymentGraph.get_for_model( self.cluster.release, graph_type='default').id, 'name': None, 'relations': [{ 'model_id': self.cluster.release.id, 'model': 'release', 'type': 'default' }] }, { 'id': self.custom_graph.id, 'name': 'custom-graph-name', 'relations': [{ 'type': 'custom-graph', 'model': 'cluster', 'model_id': self.cluster.id }] }, { 'id': default_graph.id, 'relations': [ { 'model': 'cluster', 'model_id': self.cluster.id, 'type': 'default' } ], 'name': None }, { 'id': DeploymentGraph.get_for_model( self.plugin, graph_type='default').id, 'relations': [{ 'model_id': self.plugin.id, 'model': 'plugin', 'type': 'default' }], 'name': None } ] response = self.app.get( reverse( 'DeploymentGraphCollectionHandler', kwargs={} ) + '?fetch_related=1', headers=self.default_headers ).json_body for r in response: r.pop('tasks') self.assertItemsEqual(expected_list, response) # and check filtered output response_filtered_by_type = self.app.get( reverse( 'DeploymentGraphCollectionHandler', kwargs={} ) + '?fetch_related=1&graph_types=default', headers=self.default_headers ).json_body for r in response_filtered_by_type: r.pop('tasks') self.assertItemsEqual( ( el for el in expected_list if el['relations'][0]['type'] == 'default' ), response_filtered_by_type )