From dcaf63b608a2460a79f3085c31cd428d61bc84a0 Mon Sep 17 00:00:00 2001 From: Feilong Wang Date: Fri, 22 Jun 2018 15:33:07 +1200 Subject: [PATCH] Improve Magnum cluster templates functions There are two improvements in this patch: 1. Add alias to rename xxx_cluster_template to xxx_coe_cluster_template. This a pre clean so that we can support xxx_coe_cluster to avoid conflits with Senlin's functions. 2. Support new Magnum API endpoints, /clustertemplates and /clusters. Those two endpoints added in Newton. Change-Id: I78c37f0df8f63a13c534f3dcaca2e27073f0d730 --- shade/openstackcloud.py | 53 ++++++-- shade/tests/unit/test_cluster_templates.py | 138 +++++++++++++++------ 2 files changed, 141 insertions(+), 50 deletions(-) diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index ac1290cea..a3121dadc 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -8772,11 +8772,21 @@ class OpenStackCloud( the OpenStack API call. """ with _utils.shade_exceptions("Error fetching cluster template list"): - data = self._container_infra_client.get( - '/baymodels/detail') - return self._normalize_cluster_templates( - self._get_and_munchify('baymodels', data)) + try: + data = self._container_infra_client.get('/clustertemplates') + # NOTE(flwang): Magnum adds /clustertemplates and /cluster + # to deprecate /baymodels and /bay since Newton release. So + # we're using a small tag to indicate if current + # cloud has those two new API endpoints. + self._container_infra_client._has_magnum_after_newton = True + return self._normalize_cluster_templates( + self._get_and_munchify('clustertemplates', data)) + except exc.OpenStackCloudURINotFound: + data = self._container_infra_client.get('/baymodels/detail') + return self._normalize_cluster_templates( + self._get_and_munchify('baymodels', data)) list_baymodels = list_cluster_templates + list_coe_cluster_templates = list_cluster_templates def search_cluster_templates( self, name_or_id=None, filters=None, detail=False): @@ -8796,6 +8806,7 @@ class OpenStackCloud( return _utils._filter_list( cluster_templates, name_or_id, filters) search_baymodels = search_cluster_templates + search_coe_cluster_templates = search_cluster_templates def get_cluster_template(self, name_or_id, filters=None, detail=False): """Get a cluster template by name or ID. @@ -8822,6 +8833,7 @@ class OpenStackCloud( return _utils._get_entity(self, 'cluster_template', name_or_id, filters=filters, detail=detail) get_baymodel = get_cluster_template + get_coe_cluster_template = get_cluster_template def create_cluster_template( self, name, image_id=None, keypair_id=None, coe=None, **kwargs): @@ -8849,12 +8861,18 @@ class OpenStackCloud( body['keypair_id'] = keypair_id body['coe'] = coe - cluster_template = self._container_infra_client.post( - '/baymodels', json=body) + try: + cluster_template = self._container_infra_client.post( + '/clustertemplates', json=body) + self._container_infra_client._has_magnum_after_newton = True + except exc.OpenStackCloudURINotFound: + cluster_template = self._container_infra_client.post( + '/baymodels', json=body) self.list_cluster_templates.invalidate(self) return cluster_template create_baymodel = create_cluster_template + create_coe_cluster_template = create_cluster_template def delete_cluster_template(self, name_or_id): """Delete a cluster template. @@ -8876,12 +8894,18 @@ class OpenStackCloud( return False with _utils.shade_exceptions("Error in deleting cluster template"): - self._container_infra_client.delete( - '/baymodels/{id}'.format(id=cluster_template['id'])) + if getattr(self._container_infra_client, + '_has_magnum_after_newton', False): + self._container_infra_client.delete( + '/clustertemplates/{id}'.format(id=cluster_template['id'])) + else: + self._container_infra_client.delete( + '/baymodels/{id}'.format(id=cluster_template['id'])) self.list_cluster_templates.invalidate(self) return True delete_baymodel = delete_cluster_template + delete_coe_cluster_template = delete_cluster_template @_utils.valid_kwargs('name', 'image_id', 'flavor_id', 'master_flavor_id', 'keypair_id', 'external_network_id', 'fixed_network', @@ -8918,13 +8942,20 @@ class OpenStackCloud( with _utils.shade_exceptions( "Error updating cluster template {0}".format(name_or_id)): - self._container_infra_client.patch( - '/baymodels/{id}'.format(id=cluster_template['id']), - json=patches) + if getattr(self._container_infra_client, + '_has_magnum_after_newton', False): + self._container_infra_client.patch( + '/clustertemplates/{id}'.format(id=cluster_template['id']), + json=patches) + else: + self._container_infra_client.patch( + '/baymodels/{id}'.format(id=cluster_template['id']), + json=patches) new_cluster_template = self.get_cluster_template(name_or_id) return new_cluster_template update_baymodel = update_cluster_template + update_coe_cluster_template = update_cluster_template def list_nics(self): msg = "Error fetching machine port list" diff --git a/shade/tests/unit/test_cluster_templates.py b/shade/tests/unit/test_cluster_templates.py index dbab19bdb..539539afc 100644 --- a/shade/tests/unit/test_cluster_templates.py +++ b/shade/tests/unit/test_cluster_templates.py @@ -53,10 +53,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): def test_list_cluster_templates_without_detail(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[cluster_template_obj.toDict()]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[cluster_template_obj.toDict()]))]) cluster_templates_list = self.cloud.list_cluster_templates() self.assertEqual( cluster_templates_list[0], @@ -64,10 +69,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.assert_calls() def test_list_cluster_templates_with_detail(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[cluster_template_obj.toDict()]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[cluster_template_obj.toDict()]))]) cluster_templates_list = self.cloud.list_cluster_templates(detail=True) self.assertEqual( cluster_templates_list[0], @@ -75,10 +85,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.assert_calls() def test_search_cluster_templates_by_name(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[cluster_template_obj.toDict()]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[cluster_template_obj.toDict()]))]) cluster_templates = self.cloud.search_cluster_templates( name_or_id='fake-cluster-template') @@ -89,10 +104,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): def test_search_cluster_templates_not_found(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[cluster_template_obj.toDict()]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[cluster_template_obj.toDict()]))]) cluster_templates = self.cloud.search_cluster_templates( name_or_id='non-existent') @@ -101,10 +121,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.assert_calls() def test_get_cluster_template(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[cluster_template_obj.toDict()]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[cluster_template_obj.toDict()]))]) r = self.cloud.get_cluster_template('fake-cluster-template') self.assertIsNotNone(r) @@ -113,25 +138,34 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.assert_calls() def test_get_cluster_template_not_found(self): - self.register_uris([dict( - method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', - json=dict(baymodels=[]))]) + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='GET', + uri='https://container-infra.example.com/v1/baymodels/detail', + json=dict(baymodels=[]))]) r = self.cloud.get_cluster_template('doesNotExist') self.assertIsNone(r) self.assert_calls() def test_create_cluster_template(self): - self.register_uris([dict( - method='POST', - uri='https://container-infra.example.com/v1/baymodels', - json=dict(baymodels=[cluster_template_obj.toDict()]), - validate=dict(json={ - 'coe': 'fake-coe', - 'image_id': 'fake-image', - 'keypair_id': 'fake-key', - 'name': 'fake-cluster-template'}), - )]) + self.register_uris([ + dict( + method='POST', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='POST', + uri='https://container-infra.example.com/v1/baymodels', + json=dict(baymodels=[cluster_template_obj.toDict()]), + validate=dict(json={ + 'coe': 'fake-coe', + 'image_id': 'fake-image', + 'keypair_id': 'fake-key', + 'name': 'fake-cluster-template'}),)]) self.cloud.create_cluster_template( name=cluster_template_obj.name, image_id=cluster_template_obj.image_id, @@ -140,10 +174,15 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.assert_calls() def test_create_cluster_template_exception(self): - self.register_uris([dict( - method='POST', - uri='https://container-infra.example.com/v1/baymodels', - status_code=403)]) + self.register_uris([ + dict( + method='POST', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), + dict( + method='POST', + uri='https://container-infra.example.com/v1/baymodels', + status_code=403)]) # TODO(mordred) requests here doens't give us a great story # for matching the old error message text. Investigate plumbing # an error message in to the adapter call so that we can give a @@ -158,6 +197,10 @@ class TestClusterTemplates(base.RequestsMockTestCase): def test_delete_cluster_template(self): uri = 'https://container-infra.example.com/v1/baymodels/fake-uuid' self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), dict( method='GET', uri='https://container-infra.example.com/v1/baymodels/detail', @@ -172,6 +215,10 @@ class TestClusterTemplates(base.RequestsMockTestCase): def test_update_cluster_template(self): uri = 'https://container-infra.example.com/v1/baymodels/fake-uuid' self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + status_code=404), dict( method='GET', uri='https://container-infra.example.com/v1/baymodels/detail', @@ -189,7 +236,7 @@ class TestClusterTemplates(base.RequestsMockTestCase): )), dict( method='GET', - uri='https://container-infra.example.com/v1/baymodels/detail', + uri='https://container-infra.example.com/v1/clustertemplates', # This json value is not meaningful to the test - it just has # to be valid. json=dict(baymodels=[cluster_template_obj.toDict()])), @@ -198,3 +245,16 @@ class TestClusterTemplates(base.RequestsMockTestCase): self.cloud.update_cluster_template( 'fake-uuid', 'replace', name=new_name) self.assert_calls() + + def test_get_coe_cluster_template(self): + self.register_uris([ + dict( + method='GET', + uri='https://container-infra.example.com/v1/clustertemplates', + json=dict(clustertemplates=[cluster_template_obj.toDict()]))]) + + r = self.cloud.get_coe_cluster_template('fake-cluster-template') + self.assertIsNotNone(r) + self.assertDictEqual( + r, self.cloud._normalize_cluster_template(cluster_template_obj)) + self.assert_calls()