From 2f52b2fddbd30dfa68d83e3da32030fa07940ea3 Mon Sep 17 00:00:00 2001 From: Hirotaka Wakabayashi Date: Fri, 22 Apr 2022 13:41:05 +0900 Subject: Uses glance to get image_id when creating a cluster This PR uses glance to get a valid image_id when creating a cluster. Clusters API currently checks the "image_id" column in "datastore_versions" table, which has no valid image_id(NULL) since Victoria due to the following code and docs change[1]. The original problem of this patch is that nova api throws BadRequest exception with "Block Device Mapping is Invalid" message when creating a cluster. [1]: https://opendev.org/openstack/trove/commit/1d24b65052bbfb8f7dff5744c7bb44a58a2336c6 Task: 45004 Story: 2009982 Change-Id: I2a2932e261f47d9c8ec275bf9bd41b26983230c7 --- trove/cluster/models.py | 21 +++++++++++++++++---- trove/cluster/service.py | 15 ++++++++++++++- .../cluster/experimental/cassandra/api.py | 3 ++- .../cluster/experimental/galera_common/api.py | 14 ++++++++------ .../strategies/cluster/experimental/mongodb/api.py | 3 ++- .../strategies/cluster/experimental/redis/api.py | 3 ++- .../strategies/cluster/experimental/vertica/api.py | 3 ++- .../unittests/cluster/test_cluster_controller.py | 2 +- .../cluster/test_cluster_pxc_controller.py | 2 +- .../cluster/test_cluster_redis_controller.py | 2 +- .../cluster/test_cluster_vertica_controller.py | 2 +- 11 files changed, 51 insertions(+), 19 deletions(-) (limited to 'trove') diff --git a/trove/cluster/models.py b/trove/cluster/models.py index e248d528..90f5f32f 100644 --- a/trove/cluster/models.py +++ b/trove/cluster/models.py @@ -260,14 +260,16 @@ class Cluster(object): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): locality = srv_grp.ServerGroup.build_scheduler_hint( context, locality, name) api_strategy = strategy.load_api_strategy(datastore_version.manager) return api_strategy.cluster_class.create(context, name, datastore, datastore_version, instances, extended_properties, - locality, configuration) + locality, configuration, + image_id) def validate_cluster_available(self, valid_states=[ClusterTasks.NONE]): if self.db_info.task_status not in valid_states: @@ -326,7 +328,18 @@ class Cluster(object): instance_type = instance_type.split(',') instance['instance_type'] = instance_type instances.append(instance) - return self.grow(instances) + + # Since Victoria, guest agent uses docker. + # Get image_id from glance if image_id in datastore_versions + # table is NULL. + image_id = self.ds_version.image_id + if not image_id: + glance_client = clients.create_glance_client(context) + image_id = common_glance.get_image_id( + glance_client, self.ds_version.image_id, + self.ds_version.image_tags) + return self.grow(instances, image_id) + elif action == 'shrink': context.notification = DBaaSClusterShrink(context, request=req) instance_ids = [instance['id'] for instance in param] @@ -371,7 +384,7 @@ class Cluster(object): else: raise exception.BadRequest(_("Action %s not supported") % action) - def grow(self, instances): + def grow(self, instances, image_id=None): raise exception.BadRequest(_("Action 'grow' not supported")) def shrink(self, instance_ids): diff --git a/trove/cluster/service.py b/trove/cluster/service.py index dc5fe02f..96e66f4c 100644 --- a/trove/cluster/service.py +++ b/trove/cluster/service.py @@ -20,7 +20,9 @@ from trove.cluster import models from trove.cluster import views from trove.common import apischema from trove.common import cfg +from trove.common import clients from trove.common import exception +from trove.common import glance as common_glance from trove.common.i18n import _ from trove.common import notification from trove.common.notification import StartNotification @@ -172,6 +174,16 @@ class ClusterController(wsgi.Controller): datastore, datastore_version = ( datastore_models.get_datastore_version(**datastore_args)) + # Since Victoria, guest agent uses docker. + # Get image_id from glance if image_id in datastore_versions table + # is NULL. + image_id = None + if not datastore_version.image_id: + glance_client = clients.create_glance_client(context) + image_id = common_glance.get_image_id( + glance_client, datastore_version.image_id, + datastore_version.image_tags) + extended_properties = body['cluster'].get('extended_properties', {}) try: @@ -228,7 +240,8 @@ class ClusterController(wsgi.Controller): cluster = models.Cluster.create(context, name, datastore, datastore_version, instances, extended_properties, - locality, configuration) + locality, configuration, + image_id) cluster.locality = locality view = views.load_view(cluster, req=req, load_servers=False) return wsgi.Result(view.data(), 200) diff --git a/trove/common/strategies/cluster/experimental/cassandra/api.py b/trove/common/strategies/cluster/experimental/cassandra/api.py index e5b9e6ce..f996de3d 100644 --- a/trove/common/strategies/cluster/experimental/cassandra/api.py +++ b/trove/common/strategies/cluster/experimental/cassandra/api.py @@ -81,7 +81,8 @@ class CassandraCluster(models.Cluster): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): LOG.debug("Processing a request for creating a new cluster.") # Updating Cluster Task. diff --git a/trove/common/strategies/cluster/experimental/galera_common/api.py b/trove/common/strategies/cluster/experimental/galera_common/api.py index dde0b014..1f3a4685 100644 --- a/trove/common/strategies/cluster/experimental/galera_common/api.py +++ b/trove/common/strategies/cluster/experimental/galera_common/api.py @@ -78,7 +78,7 @@ class GaleraCommonCluster(cluster_models.Cluster): @staticmethod def _create_instances(context, db_info, datastore, datastore_version, instances, extended_properties, locality, - configuration_id): + configuration_id, image_id): member_config = {"id": db_info.id, "instance_type": "member"} name_index = int(time.time()) @@ -91,7 +91,8 @@ class GaleraCommonCluster(cluster_models.Cluster): return [Instance.create(context, instance['name'], instance['flavor_id'], - datastore_version.image_id, + datastore_version.image_id + if datastore_version.image_id else image_id, [], [], datastore, datastore_version, instance.get('volume_size', None), @@ -111,7 +112,8 @@ class GaleraCommonCluster(cluster_models.Cluster): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): LOG.debug("Initiating Galera cluster creation.") ds_conf = CONF.get(datastore_version.manager) # Check number of instances is at least min_cluster_member_count @@ -129,7 +131,7 @@ class GaleraCommonCluster(cluster_models.Cluster): cls._create_instances(context, db_info, datastore, datastore_version, instances, extended_properties, locality, - configuration) + configuration, image_id) # Calling taskmanager to further proceed for cluster-configuration task_api.load(context, datastore_version.manager).create_cluster( @@ -137,7 +139,7 @@ class GaleraCommonCluster(cluster_models.Cluster): return cls(context, db_info, datastore, datastore_version) - def grow(self, instances): + def grow(self, instances, image_id=None): LOG.debug("Growing cluster %s.", self.id) self.validate_cluster_available() @@ -156,7 +158,7 @@ class GaleraCommonCluster(cluster_models.Cluster): configuration_id = self.db_info.configuration_id new_instances = self._create_instances( context, db_info, datastore, datastore_version, instances, - None, locality, configuration_id) + None, locality, configuration_id, image_id) task_api.load(context, datastore_version.manager).grow_cluster( db_info.id, [instance.id for instance in new_instances]) diff --git a/trove/common/strategies/cluster/experimental/mongodb/api.py b/trove/common/strategies/cluster/experimental/mongodb/api.py index 66413fa5..6c731fd3 100644 --- a/trove/common/strategies/cluster/experimental/mongodb/api.py +++ b/trove/common/strategies/cluster/experimental/mongodb/api.py @@ -58,7 +58,8 @@ class MongoDbCluster(models.Cluster): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): if configuration: raise exception.ConfigurationNotSupported() diff --git a/trove/common/strategies/cluster/experimental/redis/api.py b/trove/common/strategies/cluster/experimental/redis/api.py index ea1c629b..4fd5ddc6 100644 --- a/trove/common/strategies/cluster/experimental/redis/api.py +++ b/trove/common/strategies/cluster/experimental/redis/api.py @@ -103,7 +103,8 @@ class RedisCluster(models.Cluster): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): LOG.debug("Initiating cluster creation.") if configuration: diff --git a/trove/common/strategies/cluster/experimental/vertica/api.py b/trove/common/strategies/cluster/experimental/vertica/api.py index 9bc34571..1151f4d7 100644 --- a/trove/common/strategies/cluster/experimental/vertica/api.py +++ b/trove/common/strategies/cluster/experimental/vertica/api.py @@ -134,7 +134,8 @@ class VerticaCluster(models.Cluster): @classmethod def create(cls, context, name, datastore, datastore_version, - instances, extended_properties, locality, configuration): + instances, extended_properties, locality, configuration, + image_id=None): LOG.debug("Initiating cluster creation.") if configuration: diff --git a/trove/tests/unittests/cluster/test_cluster_controller.py b/trove/tests/unittests/cluster/test_cluster_controller.py index 59dfc6a9..1d745377 100644 --- a/trove/tests/unittests/cluster/test_cluster_controller.py +++ b/trove/tests/unittests/cluster/test_cluster_controller.py @@ -244,7 +244,7 @@ class TestClusterController(trove_testtools.TestCase): mock_cluster_create.assert_called_with(context, 'products', datastore, datastore_version, instances, {}, - self.locality, None) + self.locality, None, None) @patch.object(Cluster, 'load') def test_show_cluster(self, diff --git a/trove/tests/unittests/cluster/test_cluster_pxc_controller.py b/trove/tests/unittests/cluster/test_cluster_pxc_controller.py index 24c29cff..11d250c9 100644 --- a/trove/tests/unittests/cluster/test_cluster_pxc_controller.py +++ b/trove/tests/unittests/cluster/test_cluster_pxc_controller.py @@ -159,7 +159,7 @@ class TestClusterController(trove_testtools.TestCase): self.controller.create(req, body, tenant_id) mock_cluster_create.assert_called_with(context, 'products', datastore, datastore_version, - instances, {}, None, None) + instances, {}, None, None, None) @patch.object(Cluster, 'load') def test_show_cluster(self, diff --git a/trove/tests/unittests/cluster/test_cluster_redis_controller.py b/trove/tests/unittests/cluster/test_cluster_redis_controller.py index e8e931c9..2d8750c5 100644 --- a/trove/tests/unittests/cluster/test_cluster_redis_controller.py +++ b/trove/tests/unittests/cluster/test_cluster_redis_controller.py @@ -196,7 +196,7 @@ class TestClusterController(trove_testtools.TestCase): self.controller.create(req, body, tenant_id) mock_cluster_create.assert_called_with(context, 'products', datastore, datastore_version, - instances, {}, None, None) + instances, {}, None, None, None) @patch.object(Cluster, 'load') def test_show_cluster(self, diff --git a/trove/tests/unittests/cluster/test_cluster_vertica_controller.py b/trove/tests/unittests/cluster/test_cluster_vertica_controller.py index 9d656a7e..15016f92 100644 --- a/trove/tests/unittests/cluster/test_cluster_vertica_controller.py +++ b/trove/tests/unittests/cluster/test_cluster_vertica_controller.py @@ -159,7 +159,7 @@ class TestClusterController(trove_testtools.TestCase): self.controller.create(req, body, tenant_id) mock_cluster_create.assert_called_with(context, 'products', datastore, datastore_version, - instances, {}, None, None) + instances, {}, None, None, None) @patch.object(Cluster, 'load') def test_show_cluster(self, -- cgit v1.2.1