Support database version image tags for creating instance

Change-Id: If6ffacb5bab1aa5ffc51dd5678bd110c0beeb51d
This commit is contained in:
Lingxian Kong 2020-10-09 11:50:48 +13:00
parent 1d24b65052
commit c1be8a41d9
7 changed files with 120 additions and 10 deletions

View File

@ -60,8 +60,8 @@ To create a datastore version:
.. code-block:: console
openstack datastore version create 5.7.29 mysql mysql "" \
--image-tags trove,mysql \
--active --default
--image-tags trove,mysql \
--active --default
#. Load validation rules for configuration groups
@ -121,4 +121,19 @@ version for testing purpose, to do that:
.. code-block:: console
$ openstack datastore version <version-id> --disable
$ openstack datastore version set <version-id> --disable
Replace image ID with tags
~~~~~~~~~~~~~~~~~~~~~~~~~~
For datastore versions what are created using image ID, it's easy to switch to
image tags without affecting the existing instances. New instances will be
created by the image ID (the most recently uploaded) that getting from Glance
using image tags. To do that, as the cloud admin user:
.. code-block:: console
$ openstack datastore version set <version-id> --image-tags trove,mysql
Ignoring ``--image`` means removing the image ID from the datastore version if
it's associated.

View File

@ -33,7 +33,9 @@ Verify operation of the Database service.
.. code-block:: console
$ openstack datastore version create 5.7.29 mysql mysql "" trove,mysql --active --default
$ openstack datastore version create 5.7.29 mysql mysql "" \
--image-tags trove,mysql \
--active --default
#. Create a database `instance
<http://docs.openstack.org/user-guide/create_db.html>`_.

View File

@ -26,6 +26,8 @@ def get_image_id(client, image_id, image_tags):
return image_id
elif image_tags:
if isinstance(image_tags, str):
image_tags = image_tags.split(',')
filters = {'tag': image_tags, 'status': 'active'}
images = list(client.images.list(
filters=filters, sort='created_at:desc', limit=1))

View File

@ -24,6 +24,7 @@ import trove.common.apischema as 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 neutron
from trove.common import notification
@ -414,7 +415,13 @@ class InstanceController(wsgi.Controller):
datastore, datastore_version = ds_models.get_datastore_version(
**datastore_args)
image_id = datastore_version.image_id
# If only image_tags is configured in the datastore version, get
# the image ID using the tags.
glance_client = clients.create_glance_client(context)
image_id = common_glance.get_image_id(
glance_client, datastore_version.image_id,
datastore_version.image_tags)
LOG.info(f'Using image {image_id} for creating instance')
databases = populate_validated_databases(
body['instance'].get('databases', []))

View File

@ -50,11 +50,7 @@ class TestDatastoreVersionController(trove_testtools.TestCase):
@classmethod
def tearDownClass(cls):
versions = models.DatastoreVersions.load_all(only_active=False)
for ver in versions:
ver.delete()
cls.ds.delete()
util.cleanup_db()
super(TestDatastoreVersionController, cls).tearDownClass()

View File

@ -0,0 +1,80 @@
# Copyright 2020 Catalyst Cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from unittest import mock
from trove.common import clients
from trove.datastore import models as ds_models
from trove.instance import service
from trove.tests.unittests import trove_testtools
from trove.tests.unittests.util import util
class TestInstanceController(trove_testtools.TestCase):
@classmethod
def setUpClass(cls):
util.init_db()
cls.ds_name = cls.random_name('datastore',
prefix='TestInstanceController')
ds_models.update_datastore(name=cls.ds_name, default_version=None)
cls.ds = ds_models.Datastore.load(cls.ds_name)
ds_models.update_datastore_version(
cls.ds_name, 'test_image_id', 'mysql', cls.random_uuid(), [], '',
1)
ds_models.update_datastore_version(
cls.ds_name, 'test_image_tags', 'mysql', '', ['trove', 'mysql'],
'', 1)
cls.ds_version_imageid = ds_models.DatastoreVersion.load(
cls.ds, 'test_image_id')
cls.ds_version_imagetags = ds_models.DatastoreVersion.load(
cls.ds, 'test_image_tags')
cls.controller = service.InstanceController()
super(TestInstanceController, cls).setUpClass()
@classmethod
def tearDownClass(cls):
util.cleanup_db()
super(TestInstanceController, cls).tearDownClass()
@mock.patch.object(clients, 'create_glance_client')
@mock.patch('trove.instance.models.Instance.create')
def test_create_by_ds_version_image_tags(self, mock_model_create,
mock_create_client):
mock_glance_client = mock.MagicMock()
mock_glance_client.images.list.return_value = [
{'id': self.random_uuid()}]
mock_create_client.return_value = mock_glance_client
body = {
'instance': {
'name': self.random_name(name='instance',
prefix='TestInstanceController'),
'flavorRef': self.random_uuid(),
'datastore': {
'type': self.ds_name,
'version': self.ds_version_imagetags.name
}
}
}
ret = self.controller.create(mock.MagicMock(), body, mock.ANY)
self.assertEqual(200, ret.status)
mock_glance_client.images.list.assert_called_once_with(
filters={'tag': ['trove', 'mysql'], 'status': 'active'},
sort='created_at:desc', limit=1
)

View File

@ -31,3 +31,11 @@ def init_db():
db_api.db_sync(CONF)
session.configure_db(CONF)
DB_SETUP = True
def cleanup_db():
with LOCK:
global DB_SETUP
if DB_SETUP:
session.clean_db()
DB_SETUP = False