Merge "Add 'version' to datastore version"

This commit is contained in:
Zuul 2020-11-19 02:20:57 +00:00 committed by Gerrit Code Review
commit a81cd89375
11 changed files with 170 additions and 41 deletions

View File

@ -481,10 +481,11 @@ function create_guest_image {
--property hw_rng_model='virtio' \
--file ${image_file} \
-c id -f value)
echo "Glance image ${glance_image_id} uploaded"
echo "Register the image in datastore"
$TROVE_MANAGE datastore_update $TROVE_DATASTORE_TYPE ""
$TROVE_MANAGE datastore_version_update $TROVE_DATASTORE_TYPE $TROVE_DATASTORE_VERSION $TROVE_DATASTORE_TYPE $glance_image_id "trove" "" 1
$TROVE_MANAGE datastore_version_update $TROVE_DATASTORE_TYPE $TROVE_DATASTORE_VERSION $TROVE_DATASTORE_TYPE "" "trove" "" 1
$TROVE_MANAGE datastore_update $TROVE_DATASTORE_TYPE $TROVE_DATASTORE_VERSION
echo "Add parameter validation rules if available"

View File

@ -521,11 +521,8 @@ function set_bin_path() {
}
function cmd_set_datastore() {
local IMAGEID=$1
rd_manage datastore_update "$datastore" ""
# trove-manage datastore_version_update <datastore_name> <version_name> <datastore_manager> <image_id> <image_tags> <packages> <active>
rd_manage datastore_version_update "${DATASTORE_TYPE}" "${DATASTORE_VERSION}" "${DATASTORE_TYPE}" ${IMAGEID} "trove" "" 1
rd_manage datastore_version_update "${DATASTORE_TYPE}" "${DATASTORE_VERSION}" "${DATASTORE_TYPE}" "" "trove" "" 1
rd_manage datastore_update "${DATASTORE_TYPE}" "${DATASTORE_VERSION}"
if [[ -f "$PATH_TROVE"/trove/templates/${DATASTORE_TYPE}/validation-rules.json ]]; then
@ -781,7 +778,7 @@ function cmd_build_and_upload_image() {
exclaim "Using Glance image ID: $glance_imageid"
exclaim "Updating Datastores"
cmd_set_datastore "${glance_imageid}"
cmd_set_datastore
}

View File

@ -62,15 +62,18 @@ class Commands(object):
print(e)
def datastore_version_update(self, datastore, version_name, manager,
image_id, image_tags, packages, active):
image_id, image_tags, packages, active,
version=None):
try:
datastore_models.update_datastore_version(datastore,
version_name,
manager,
image_id,
image_tags,
packages, active)
print("Datastore version '%s' updated." % version_name)
packages, active,
version=version)
print("Datastore version '%s(%s)' updated." %
(version_name, version))
except exception.DatastoreNotFound as e:
print(e)
@ -223,6 +226,10 @@ def main():
'active', type=int,
help='Whether the datastore version is active or not. '
'Accepted values are 0 and 1.')
parser.add_argument(
'--version',
help='The version number of the datastore version, e.g. 5.7.30. '
'If not specified, use <version_name> as default value.')
parser = subparser.add_parser(
'db_recreate', description='Drop the database and recreate it.')

View File

@ -979,7 +979,8 @@ mgmt_datastore_version = {
"image": uuid,
"image_tags": image_tags,
"active": {"enum": [True, False]},
"default": {"enum": [True, False]}
"default": {"enum": [True, False]},
"version": non_empty_string
}
}
}

View File

@ -180,7 +180,8 @@ class DatastoreVersionInactive(TroveError):
class DatastoreVersionAlreadyExists(BadRequest):
message = _("A datastore version with the name '%(name)s' already exists.")
message = _("The datastore version '%(name)s(%(version)s)' already "
"exists.")
class DatastoreVersionsExist(BadRequest):

View File

@ -16,6 +16,7 @@
# under the License.
from oslo_log import log as logging
from oslo_utils import uuidutils
from trove.common import cfg
from trove.common.clients import create_nova_client
@ -63,7 +64,7 @@ class DBCapabilityOverrides(dbmodels.DatabaseModelBase):
class DBDatastoreVersion(dbmodels.DatabaseModelBase):
_data_fields = ['datastore_id', 'name', 'image_id', 'image_tags',
'packages', 'active', 'manager']
'packages', 'active', 'manager', 'version']
_table_name = 'datastore_versions'
@ -399,18 +400,20 @@ class DatastoreVersion(object):
return "%s(%s)" % (self.name, self.id)
@classmethod
def load(cls, datastore, id_or_name):
try:
def load(cls, datastore, id_or_name, version=None):
if uuidutils.is_uuid_like(id_or_name):
return cls(DBDatastoreVersion.find_by(datastore_id=datastore.id,
id=id_or_name))
except exception.ModelNotFoundError:
versions = DBDatastoreVersion.find_all(datastore_id=datastore.id,
name=id_or_name)
if versions.count() == 0:
raise exception.DatastoreVersionNotFound(version=id_or_name)
if versions.count() > 1:
raise exception.NoUniqueMatch(name=id_or_name)
return cls(versions.first())
version = version or id_or_name
versions = DBDatastoreVersion.find_all(datastore_id=datastore.id,
name=id_or_name,
version=version)
if versions.count() == 0:
raise exception.DatastoreVersionNotFound(version=version)
if versions.count() > 1:
raise exception.NoUniqueMatch(name=id_or_name)
return cls(versions.first())
@classmethod
def load_by_uuid(cls, uuid):
@ -474,6 +477,10 @@ class DatastoreVersion(object):
return self._capabilities
@property
def version(self):
return self.db_info.version
class DatastoreVersions(object):
@ -581,26 +588,30 @@ def update_datastore(name, default_version):
def update_datastore_version(datastore, name, manager, image_id, image_tags,
packages, active):
packages, active, version=None):
"""Create or update datastore version."""
version = version or name
db_api.configure_db(CONF)
datastore = Datastore.load(datastore)
try:
version = DBDatastoreVersion.find_by(datastore_id=datastore.id,
name=name)
ds_version = DBDatastoreVersion.find_by(datastore_id=datastore.id,
name=name,
version=version)
except exception.ModelNotFoundError:
# Create a new one
version = DBDatastoreVersion()
version.id = utils.generate_uuid()
version.name = name
version.datastore_id = datastore.id
version.manager = manager
version.image_id = image_id
version.image_tags = (",".join(image_tags)
if type(image_tags) is list else image_tags)
version.packages = packages
version.active = active
ds_version = DBDatastoreVersion()
ds_version.id = utils.generate_uuid()
ds_version.name = name
ds_version.version = version
ds_version.datastore_id = datastore.id
ds_version.manager = manager
ds_version.image_id = image_id
ds_version.image_tags = (",".join(image_tags)
if type(image_tags) is list else image_tags)
ds_version.packages = packages
ds_version.active = active
db_api.save(version)
db_api.save(ds_version)
class DatastoreVersionMetadata(object):

View File

@ -80,6 +80,7 @@ class DatastoreVersionView(object):
datastore_version_dict = {
"id": self.datastore_version.id,
"name": self.datastore_version.name,
"version": self.datastore_version.version,
"links": self._build_links(),
}
if include_datastore_id:

View File

@ -0,0 +1,71 @@
# Copyright 2020 Catalyst Cloud
# All Rights Reserved.
#
# 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 migrate.changeset.constraint import UniqueConstraint
from sqlalchemy import text
from sqlalchemy.schema import Column
from sqlalchemy.schema import MetaData
from sqlalchemy.sql.expression import select
from sqlalchemy.sql.expression import update
from trove.db.sqlalchemy import utils as db_utils
from trove.db.sqlalchemy.migrate_repo.schema import String
from trove.db.sqlalchemy.migrate_repo.schema import Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
ds_table = Table('datastores', meta, autoload=True)
ds_version_table = Table('datastore_versions', meta, autoload=True)
ds_version_table.create_column(
Column('version', String(255), nullable=True))
ds_versions = select(
columns=[text("id"), text("name")],
from_obj=ds_version_table
).execute()
# Use 'name' value as init 'version' value
for version in ds_versions:
update(
table=ds_version_table,
whereclause=text("id='%s'" % version.id),
values=dict(version=version.name)
).execute()
# Change unique constraint, need to drop the foreign key first and add back
# later
constraint_names = db_utils.get_foreign_key_constraint_names(
engine=migrate_engine,
table='datastore_versions',
columns=['datastore_id'],
ref_table='datastores',
ref_columns=['id'])
db_utils.drop_foreign_key_constraints(
constraint_names=constraint_names,
columns=[ds_version_table.c.datastore_id],
ref_columns=[ds_table.c.id])
UniqueConstraint('datastore_id', 'name', name='ds_versions',
table=ds_version_table).drop()
UniqueConstraint('datastore_id', 'name', 'version', name='ds_versions',
table=ds_version_table).create()
db_utils.create_foreign_key_constraints(
constraint_names=constraint_names,
columns=[ds_version_table.c.datastore_id],
ref_columns=[ds_table.c.id])

View File

@ -49,6 +49,9 @@ class DatastoreVersionController(wsgi.Controller):
packages = ','.join(packages)
active = body['version']['active']
default = body['version'].get('default', False)
# For backward compatibility, use name as default value for version if
# not specified
version_str = body['version'].get('version', version_name)
LOG.info("Tenant: '%(tenant)s' is adding the datastore "
"version: '%(version)s' to datastore: '%(datastore)s'",
@ -72,12 +75,15 @@ class DatastoreVersionController(wsgi.Controller):
datastore.save()
try:
models.DatastoreVersion.load(datastore, version_name)
raise exception.DatastoreVersionAlreadyExists(name=version_name)
models.DatastoreVersion.load(datastore, version_name,
version=version_str)
raise exception.DatastoreVersionAlreadyExists(
name=version_name, version=version_str)
except exception.DatastoreVersionNotFound:
models.update_datastore_version(datastore.name, version_name,
manager, image_id, image_tags,
packages, active)
packages, active,
version=version_str)
if default:
models.update_datastore(datastore.name, version_name)

View File

@ -22,6 +22,7 @@ class DatastoreVersionView(object):
datastore_version_dict = {
"id": self.datastore_version.id,
"name": self.datastore_version.name,
"version": self.datastore_version.version,
"datastore_id": self.datastore_version.datastore_id,
"datastore_name": self.datastore_version.datastore_name,
"datastore_manager": self.datastore_version.manager,

View File

@ -32,6 +32,7 @@ class TestDatastoreVersionController(trove_testtools.TestCase):
def setUpClass(cls):
util.init_db()
cls.ds_name = cls.random_name('datastore')
cls.ds_version_number = '5.7.30'
models.update_datastore(name=cls.ds_name, default_version=None)
models.update_datastore_version(
@ -39,11 +40,12 @@ class TestDatastoreVersionController(trove_testtools.TestCase):
1)
models.update_datastore_version(
cls.ds_name, 'test_vr2', 'mysql', cls.random_uuid(), '', 'pkg-1',
1)
1, version=cls.ds_version_number)
cls.ds = models.Datastore.load(cls.ds_name)
cls.ds_version1 = models.DatastoreVersion.load(cls.ds, 'test_vr1')
cls.ds_version2 = models.DatastoreVersion.load(cls.ds, 'test_vr2')
cls.ds_version2 = models.DatastoreVersion.load(
cls.ds, 'test_vr2', version=cls.ds_version_number)
cls.version_controller = DatastoreVersionController()
super(TestDatastoreVersionController, cls).setUpClass()
@ -136,6 +138,34 @@ class TestDatastoreVersionController(trove_testtools.TestCase):
new_ver = models.DatastoreVersion.load(self.ds, ver_name)
self.assertEqual(image_id, new_ver.image_id)
self.assertEqual(ver_name, new_ver.version)
@patch.object(clients, 'create_glance_client')
def test_create_same_version_number(self, mock_glance_client):
image_id = self.random_uuid()
ver_name = self.random_name('dsversion')
body = {
"version": {
"datastore_name": self.ds_name,
"name": ver_name,
"datastore_manager": "mysql",
"image": image_id,
"image_tags": [],
"packages": "",
"active": True,
"default": False,
"version": self.ds_version_number
}
}
output = self.version_controller.create(MagicMock(), body, mock.ANY)
self.assertEqual(202, output.status)
new_ver = models.DatastoreVersion.load(self.ds, ver_name,
version=self.ds_version_number)
self.assertEqual(image_id, new_ver.image_id)
self.assertEqual(ver_name, new_ver.name)
self.assertEqual(self.ds_version_number, new_ver.version)
self.assertNotEqual(self.ds_version2.id, new_ver.id)
@patch.object(clients, 'create_glance_client')
def test_create_by_image_tags(self, mock_create_client):
@ -304,6 +334,8 @@ class TestDatastoreVersionController(trove_testtools.TestCase):
output._data['version']['packages'])
self.assertEqual(self.ds_version2.active,
output._data['version']['active'])
self.assertEqual(self.ds_version2.version,
output._data['version']['version'])
def test_show_image_tags(self):
ver_name = self.random_name('dsversion')