Merge "Implements Datastore Registration API"

This commit is contained in:
Jenkins 2015-09-04 00:34:33 +00:00 committed by Gerrit Code Review
commit 8bec82524d
11 changed files with 764 additions and 0 deletions

View File

@ -605,3 +605,53 @@ upgrade = {
}
}
}
package_list = {
"type": "array",
"minItems": 0,
"uniqueItems": True,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"pattern": "^.*[0-9a-zA-Z]+.*$"
}
}
mgmt_datastore_version = {
"create": {
"name": "mgmt_datastore_version:create",
"type": "object",
"required": ["version"],
"properties": {
"version": {
"type": "object",
"required": ["name", "datastore_name", "image", "active"],
"additionalProperties": True,
"properties": {
"name": non_empty_string,
"datastore_name": non_empty_string,
"datastore_manager": non_empty_string,
"packages": package_list,
"image": uuid,
"active": {"enum": [True, False]},
"default": {"enum": [True, False]}
}
}
}
},
"edit": {
"name": "mgmt_datastore_version:edit",
"type": "object",
"required": [],
"additionalProperties": True,
"properties": {
"datastore_manager": non_empty_string,
"packages": package_list,
"image": uuid,
"active": {"enum": [True, False]},
"default": {"enum": [True, False]},
}
}
}

View File

@ -531,3 +531,13 @@ class BackupTooLarge(TroveError):
message = _("Backup is too large for given flavor or volume. "
"Backup size: %(backup_size)s GBs. "
"Available size: %(disk_size)s GBs.")
class ImageNotFound(NotFound):
message = _("Image %(uuid)s cannot be found.")
class DatastoreVersionAlreadyExists(BadRequest):
message = _("A datastore version with the name '%(name)s' already exists.")

View File

@ -408,6 +408,9 @@ class DatastoreVersion(object):
except exception.ModelNotFoundError:
raise exception.DatastoreVersionNotFound(version=uuid)
def delete(self):
self.db_info.delete()
@property
def id(self):
return self.db_info.id
@ -444,6 +447,11 @@ class DatastoreVersion(object):
def manager(self):
return self.db_info.manager
@property
def default(self):
datastore = Datastore.load(self.datastore_id)
return (datastore.default_version_id == self.db_info.id)
@property
def capabilities(self):
if self._capabilities is None:

View File

@ -0,0 +1,155 @@
# Copyright [2015] Hewlett-Packard Development Company, L.P.
#
# 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 novaclient import exceptions as nova_exceptions
from oslo_log import log as logging
from trove.common import apischema as apischema
from trove.common.auth import admin_context
from trove.common import exception
from trove.common.i18n import _
from trove.common import remote
from trove.common import utils
from trove.common import wsgi
from trove.datastore import models
from trove.extensions.mgmt.datastores import views
LOG = logging.getLogger(__name__)
class DatastoreVersionController(wsgi.Controller):
"""Controller for datastore version registration functionality."""
schemas = apischema.mgmt_datastore_version
@admin_context
def create(self, req, body, tenant_id):
"""Adds a new datastore version."""
context = req.environ[wsgi.CONTEXT_KEY]
datastore_name = body['version']['datastore_name']
version_name = body['version']['name']
manager = body['version']['datastore_manager']
image_id = body['version']['image']
packages = body['version']['packages']
if type(packages) is list:
packages = ','.join(packages)
active = body['version']['active']
default = body['version']['default']
LOG.info(_("Tenant: '%(tenant)s' is adding the datastore "
"version: '%(version)s' to datastore: '%(datastore)s'") %
{'tenant': tenant_id, 'version': version_name,
'datastore': datastore_name})
client = remote.create_nova_client(context)
try:
client.images.get(image_id)
except nova_exceptions.NotFound:
raise exception.ImageNotFound(uuid=image_id)
try:
datastore = models.Datastore.load(datastore_name)
except exception.DatastoreNotFound:
# Create the datastore if datastore_name does not exists.
LOG.info(_("Creating datastore %s") % datastore_name)
datastore = models.DBDatastore()
datastore.id = utils.generate_uuid()
datastore.name = datastore_name
datastore.save()
try:
models.DatastoreVersion.load(datastore, version_name)
raise exception.DatastoreVersionAlreadyExists(name=version_name)
except exception.DatastoreVersionNotFound:
models.update_datastore_version(datastore.name, version_name,
manager, image_id, packages,
active)
if default:
models.update_datastore(datastore.name, version_name)
return wsgi.Result(None, 202)
@admin_context
def index(self, req, tenant_id):
"""Lists all datastore-versions for given datastore."""
db_ds_versions = models.DatastoreVersions.load_all(only_active=False)
datastore_versions = [models.DatastoreVersion.load_by_uuid(
ds_version.id) for ds_version in db_ds_versions]
return wsgi.Result(
views.DatastoreVersionsView(datastore_versions).data(), 200)
@admin_context
def show(self, req, tenant_id, id):
"""Lists details of a datastore-version for given datastore."""
datastore_version = models.DatastoreVersion.load_by_uuid(id)
return wsgi.Result(
views.DatastoreVersionView(datastore_version).data(),
200)
@admin_context
def edit(self, req, body, tenant_id, id):
"""Updates the attributes of a datastore version."""
context = req.environ[wsgi.CONTEXT_KEY]
datastore_version = models.DatastoreVersion.load_by_uuid(id)
LOG.info(_("Tenant: '%(tenant)s' is updating the datastore "
"version: '%(version)s' for datastore: '%(datastore)s'") %
{'tenant': tenant_id, 'version': datastore_version.name,
'datastore': datastore_version.datastore_name})
manager = body.get('datastore_manager', datastore_version.manager)
image_id = body.get('image', datastore_version.image_id)
active = body.get('active', datastore_version.active)
default = body.get('default', None)
packages = body.get('packages', datastore_version.packages)
if type(packages) is list:
packages = ','.join(packages)
client = remote.create_nova_client(context)
try:
client.images.get(image_id)
except nova_exceptions.NotFound:
raise exception.ImageNotFound(uuid=image_id)
models.update_datastore_version(datastore_version.datastore_name,
datastore_version.name,
manager, image_id, packages,
active)
if default:
models.update_datastore(datastore_version.datastore_name,
datastore_version.name)
elif (default is False and datastore_version.default is True):
models.update_datastore(datastore_version.datastore_name, None)
return wsgi.Result(None, 202)
@admin_context
def delete(self, req, tenant_id, id):
"""Remove an existing datastore version."""
datastore_version = models.DatastoreVersion.load_by_uuid(id)
datastore = models.Datastore.load(datastore_version.datastore_id)
LOG.info(_("Tenant: '%(tenant)s' is removing the datastore "
"version: '%(version)s' for datastore: '%(datastore)s'") %
{'tenant': tenant_id, 'version': datastore_version.name,
'datastore': datastore.name})
if datastore.default_version_id == datastore_version.id:
models.update_datastore(datastore.name, None)
datastore_version.delete()
return wsgi.Result(None, 202)

View File

@ -0,0 +1,48 @@
# Copyright [2015] Hewlett-Packard Development Company, L.P.
#
# 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.
class DatastoreVersionView(object):
def __init__(self, datastore_version):
self.datastore_version = datastore_version
def data(self):
datastore_version_dict = {
"id": self.datastore_version.id,
"name": self.datastore_version.name,
"datastore_id": self.datastore_version.datastore_id,
"datastore_name": self.datastore_version.datastore_name,
"datastore_manager": self.datastore_version.manager,
"image": self.datastore_version.image_id,
"packages": (self.datastore_version.packages.split(
',') if self.datastore_version.packages else ['']),
"active": self.datastore_version.active,
"default": self.datastore_version.default}
return {'version': datastore_version_dict}
class DatastoreVersionsView(object):
def __init__(self, datastore_versions):
self.datastore_versions = datastore_versions
def data(self):
data = []
for datastore_version in self.datastore_versions:
data.append(
DatastoreVersionView(datastore_version).data()['version'])
return {'versions': data}

View File

@ -18,6 +18,7 @@ from oslo_log import log as logging
from trove.common import extensions
from trove.extensions.mgmt.clusters.service import MgmtClusterController
from trove.extensions.mgmt.configuration import service as conf_service
from trove.extensions.mgmt.datastores.service import DatastoreVersionController
from trove.extensions.mgmt.host.instance import service as hostservice
from trove.extensions.mgmt.host.service import HostController
from trove.extensions.mgmt.instances.service import MgmtInstanceController
@ -102,4 +103,10 @@ class Mgmt(extensions.ExtensionDescriptor):
member_actions={})
resources.append(datastore_configuration_parameters)
datastore_version = extensions.ResourceExtension(
'{tenant_id}/mgmt/datastore-versions',
DatastoreVersionController(),
member_actions={})
resources.append(datastore_version)
return resources

View File

@ -0,0 +1,157 @@
# Copyright [2015] Hewlett-Packard Development Company, L.P.
#
# 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 proboscis.asserts import assert_equal
from proboscis.asserts import assert_false
from proboscis.asserts import assert_raises
from proboscis.asserts import assert_true
from proboscis import before_class
from proboscis.check import Check
from proboscis import test
from troveclient.compat import exceptions
from trove.tests.config import CONFIG
from trove.tests.util import create_client
from trove.tests.util import create_dbaas_client
from trove.tests.util import create_nova_client
from trove.tests.util import test_config
from trove.tests.util.users import Requirements
GROUP = "dbaas.api.mgmt.ds_versions"
@test(groups=[GROUP])
def mgmt_datastore_version_list_requires_admin_account():
"""Verify that an admin context is required to call this function."""
client = create_client(is_admin=False)
assert_raises(exceptions.Unauthorized, client.mgmt_datastore_versions.list)
@test(groups=[GROUP])
class MgmtDataStoreVersion(object):
"""Tests the mgmt datastore version methods."""
@before_class
def setUp(self):
"""Create client for tests."""
reqs = Requirements(is_admin=True)
self.user = CONFIG.users.find_user(reqs)
self.client = create_dbaas_client(self.user)
if test_config.nova_client is not None:
nova_user = test_config.users.find_user(
Requirements(services=["nova"]))
self.nova_client = create_nova_client(nova_user)
self.images = self.nova_client.images.list()
def _find_ds_version_by_name(self, ds_version_name):
ds_versions = self.client.mgmt_datastore_versions.list()
for ds_version in ds_versions:
if ds_version_name == ds_version.name:
return ds_version
@test
def test_mgmt_ds_version_list_original_count(self):
"""Tests the mgmt datastore version list method."""
self.ds_versions = self.client.mgmt_datastore_versions.list()
# By default we create two datastore-versions for mysql
assert_equal(2, len(self.ds_versions.items))
@test(depends_on=[test_mgmt_ds_version_list_original_count])
def test_mgmt_ds_version_list_fields_present(self):
"""Verify that all expected fields are returned by list method."""
expected_fields = [
'id',
'name',
'datastore_id',
'datastore_name',
'datastore_manager',
'image',
'packages',
'active',
'default',
]
for ds_version in self.ds_versions:
with Check() as check:
for field in expected_fields:
check.true(hasattr(ds_version, field),
"List lacks field %s." % field)
@test(depends_on=[test_mgmt_ds_version_list_original_count])
def test_mgmt_ds_version_get(self):
"""Tests the mgmt datastore version get method."""
test_version = self.ds_versions[0]
found_ds_version = self.client.mgmt_datastore_versions.get(
test_version.id)
assert_equal(test_version.name, found_ds_version.name)
assert_equal(test_version.datastore_id, found_ds_version.datastore_id)
assert_equal(test_version.datastore_name,
found_ds_version.datastore_name)
assert_equal(test_version.datastore_manager,
found_ds_version.datastore_manager)
assert_equal(test_version.image, found_ds_version.image)
assert_equal(test_version.packages, found_ds_version.packages)
assert_equal(test_version.active, found_ds_version.active)
assert_equal(test_version.default, found_ds_version.default)
@test(depends_on=[test_mgmt_ds_version_list_original_count])
def test_mgmt_ds_version_create(self):
"""Tests the mgmt datastore version create method."""
response = self.client.mgmt_datastore_versions.create(
'test_version1', 'test_ds', 'test_mgr',
self.images[0].id, ['vertica-7.1'])
assert_equal(None, response)
assert_equal(202, self.client.last_http_code)
# Since we created one more ds_version
# lets check count of total ds_versions, it should be increased by 1
new_ds_versions = self.client.mgmt_datastore_versions.list()
assert_equal(len(self.ds_versions.items) + 1,
len(new_ds_versions.items))
# Match the contents of newly created ds_version.
self.created_version = self._find_ds_version_by_name('test_version1')
assert_equal('test_version1', self.created_version.name)
assert_equal('test_ds', self.created_version.datastore_name)
assert_equal('test_mgr', self.created_version.datastore_manager)
assert_equal(self.images[0].id, self.created_version.image)
assert_equal(['vertica-7.1'], self.created_version.packages)
assert_true(self.created_version.active)
assert_false(self.created_version.default)
@test(depends_on=[test_mgmt_ds_version_create])
def test_mgmt_ds_version_patch(self):
"""Tests the mgmt datastore version edit method."""
self.client.mgmt_datastore_versions.edit(
self.created_version.id, image=self.images[1].id,
packages=['pkg1'])
assert_equal(202, self.client.last_http_code)
# Lets match the content of patched datastore
patched_ds_version = self._find_ds_version_by_name('test_version1')
assert_equal(self.images[1].id, patched_ds_version.image)
assert_equal(['pkg1'], patched_ds_version.packages)
@test(depends_on=[test_mgmt_ds_version_patch])
def test_mgmt_ds_version_delete(self):
"""Tests the mgmt datastore version delete method."""
self.client.mgmt_datastore_versions.delete(self.created_version.id)
assert_equal(202, self.client.last_http_code)
# Lets match the total count of ds_version,
# it should get back to original
ds_versions = self.client.mgmt_datastore_versions.list()
assert_equal(len(self.ds_versions.items), len(ds_versions.items))

View File

@ -23,6 +23,7 @@ from trove.tests.api import instances
from trove.tests.api import instances_actions
from trove.tests.api.mgmt import accounts
from trove.tests.api.mgmt import admin_required
from trove.tests.api.mgmt import datastore_versions
from trove.tests.api.mgmt import hosts
from trove.tests.api.mgmt import instances as mgmt_instances
from trove.tests.api.mgmt import storage
@ -82,6 +83,7 @@ black_box_groups = [
instances.GROUP_STOP,
versions.GROUP,
instances.GROUP_GUEST,
datastore_versions.GROUP,
]
proboscis.register(groups=["blackbox", "mysql"],
depends_on_groups=black_box_groups)
@ -92,6 +94,7 @@ simple_black_box_groups = [
versions.GROUP,
instances.GROUP_START_SIMPLE,
admin_required.GROUP,
datastore_versions.GROUP,
]
proboscis.register(groups=["simple_blackbox"],
depends_on_groups=simple_black_box_groups)
@ -103,6 +106,7 @@ black_box_mgmt_groups = [
instances_actions.GROUP_REBOOT,
admin_required.GROUP,
mgmt_instances.GROUP,
datastore_versions.GROUP,
]
proboscis.register(groups=["blackbox_mgmt"],
depends_on_groups=black_box_mgmt_groups)

View File

@ -0,0 +1,157 @@
# Copyright [2015] Hewlett-Packard Development Company, L.P.
#
# 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.
import jsonschema
from mock import Mock, patch, MagicMock, PropertyMock
from testtools.matchers import Is, Equals
from trove.common import exception
from trove.common import remote
from trove.datastore import models as datastore_models
from trove.extensions.mgmt.datastores.service import DatastoreVersionController
from trove.tests.unittests import trove_testtools
class TestDatastoreVersionController(trove_testtools.TestCase):
def setUp(self):
super(TestDatastoreVersionController, self).setUp()
self.controller = DatastoreVersionController()
self.version = {
"version": {
"datastore_name": "test_dsx",
"name": "test_vr1",
"datastore_manager": "mysql",
"image": "154b350d-4d86-4214-9067-9c54b230c0da",
"packages": ["mysql-server-5.6"],
"active": True,
"default": False
}
}
self.tenant_id = Mock()
context = Mock()
self.req = Mock()
self.req.environ = Mock()
self.req.environ.__getitem__ = Mock(return_value=context)
def test_get_schema_create(self):
schema = self.controller.get_schema('create', self.version)
self.assertIsNotNone(schema)
self.assertTrue('version' in schema['properties'])
def test_validate_create(self):
body = self.version
schema = self.controller.get_schema('create', body)
validator = jsonschema.Draft4Validator(schema)
self.assertTrue(validator.is_valid(body))
def test_validate_create_blankname(self):
body = self.version
body['version']['name'] = " "
schema = self.controller.get_schema('create', body)
validator = jsonschema.Draft4Validator(schema)
self.assertFalse(validator.is_valid(body))
errors = sorted(validator.iter_errors(body), key=lambda e: e.path)
self.assertThat(len(errors), Is(1))
self.assertThat(errors[0].message,
Equals("' ' does not match '^.*[0-9a-zA-Z]+.*$'"))
def test_validate_create_blank_datastore(self):
body = self.version
body['version']['datastore_name'] = ""
schema = self.controller.get_schema('create', body)
validator = jsonschema.Draft4Validator(schema)
self.assertFalse(validator.is_valid(body))
errors = sorted(validator.iter_errors(body), key=lambda e: e.path)
error_messages = [error.message for error in errors]
self.assertThat(len(errors), Is(2))
self.assertIn("'' is too short", error_messages)
self.assertIn("'' does not match '^.*[0-9a-zA-Z]+.*$'", error_messages)
@patch.object(remote, 'create_nova_client')
@patch.object(datastore_models.Datastore, 'load')
@patch.object(datastore_models.DatastoreVersion, 'load',
side_effect=exception.DatastoreVersionNotFound)
@patch.object(datastore_models, 'update_datastore_version')
def test_create_datastore_versions(self, mock_ds_version_create,
mock_ds_version_load,
mock_ds_load, mock_nova_client):
body = self.version
mock_ds_load.return_value.name = 'test_dsx'
self.controller.create(self.req, body, self.tenant_id)
mock_ds_version_create.assert_called_with(
'test_dsx', 'test_vr1', 'mysql',
'154b350d-4d86-4214-9067-9c54b230c0da',
'mysql-server-5.6', True)
@patch.object(datastore_models.DatastoreVersion, 'load_by_uuid')
def test_show_ds_version(self, mock_ds_version_load):
id = Mock()
self.controller.show(self.req, self.tenant_id, id)
mock_ds_version_load.assert_called_with(id)
@patch.object(datastore_models.Datastore, 'load')
@patch.object(datastore_models.DatastoreVersion, 'load_by_uuid')
def test_delete_ds_version(self, mock_ds_version_load, mock_ds_load):
ds_version_id = Mock()
ds_version = Mock()
mock_ds_version_load.return_value = ds_version
self.controller.delete(self.req, self.tenant_id, ds_version_id)
ds_version.delete.assert_called_with()
@patch.object(datastore_models.DatastoreVersion, 'load_by_uuid')
@patch.object(datastore_models.DatastoreVersions, 'load_all')
def test_index_ds_version(self, mock_ds_version_load_all,
mock_ds_version_load_by_uuid):
mock_id = Mock()
mock_ds_version = Mock()
mock_ds_version.id = mock_id
mock_ds_version_load_all.return_value = [mock_ds_version]
self.controller.index(self.req, self.tenant_id)
mock_ds_version_load_all.assert_called_with(only_active=False)
mock_ds_version_load_by_uuid.assert_called_with(mock_id)
@patch.object(remote, 'create_nova_client')
@patch.object(datastore_models.DatastoreVersion, 'load_by_uuid')
@patch.object(datastore_models, 'update_datastore_version')
def test_edit_datastore_versions(self, mock_ds_version_update,
mock_ds_version_load,
mock_nova_client):
body = {'image': '21c8805a-a800-4bca-a192-3a5a2519044d'}
mock_ds_version = MagicMock()
type(mock_ds_version).datastore_name = PropertyMock(
return_value=self.version['version']['datastore_name'])
type(mock_ds_version).name = PropertyMock(
return_value=self.version['version']['name'])
type(mock_ds_version).image_id = PropertyMock(
return_value=self.version['version']['image'])
type(mock_ds_version).packages = PropertyMock(
return_value=self.version['version']['packages'])
type(mock_ds_version).active = PropertyMock(
return_value=self.version['version']['active'])
type(mock_ds_version).manager = PropertyMock(
return_value=self.version['version']['datastore_manager'])
mock_ds_version_load.return_value = mock_ds_version
self.controller.edit(self.req, body, self.tenant_id, Mock())
mock_ds_version_update.assert_called_with(
'test_dsx', 'test_vr1', 'mysql',
'21c8805a-a800-4bca-a192-3a5a2519044d',
'mysql-server-5.6', True)

View File

@ -0,0 +1,168 @@
# Copyright [2015] Hewlett-Packard Development Company, L.P.
#
# 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 mock import Mock, patch
from novaclient import exceptions as nova_exceptions
from trove.common import exception
from trove.common import remote
from trove.datastore import models
from trove.extensions.mgmt.datastores.service import DatastoreVersionController
from trove.tests.unittests import trove_testtools
from trove.tests.unittests.util import util
class TestDatastoreVersion(trove_testtools.TestCase):
def setUp(self):
super(TestDatastoreVersion, self).setUp()
util.init_db()
models.update_datastore(name='test_ds', default_version=None)
models.update_datastore_version(
'test_ds', 'test_vr1', 'mysql',
'154b350d-4d86-4214-9067-9c54b230c0da', 'pkg-1', '1')
models.update_datastore_version(
'test_ds', 'test_vr2', 'mysql',
'154b350d-4d86-4214-9067-9c54b230c0da', 'pkg-1', '1')
self.ds = models.Datastore.load('test_ds')
self.ds_version1 = models.DatastoreVersion.load(self.ds, 'test_vr1')
self.ds_version2 = models.DatastoreVersion.load(self.ds, 'test_vr2')
self.context = Mock()
self.req = Mock()
self.req.environ = Mock()
self.req.environ.__getitem__ = Mock(return_value=self.context)
self.tenant_id = Mock()
self.version_controller = DatastoreVersionController()
def tearDown(self):
super(TestDatastoreVersion, self).tearDown()
@patch.object(remote, 'create_nova_client')
def test_version_create(self, mock_nova_client):
body = {"version": {
"datastore_name": "test_ds",
"name": "test_vr",
"datastore_manager": "mysql",
"image": "image-id",
"packages": "test-pkg",
"active": True,
"default": True}}
output = self.version_controller.create(
self.req, body, self.tenant_id)
self.assertEqual(202, output.status)
@patch.object(remote, 'create_nova_client')
@patch.object(models.DatastoreVersion, 'load')
def test_fail_already_exists_version_create(self, mock_load,
mock_nova_client):
body = {"version": {
"datastore_name": "test_ds",
"name": "test_new_vr",
"datastore_manager": "mysql",
"image": "image-id",
"packages": "test-pkg",
"active": True,
"default": True}}
self.assertRaisesRegexp(
exception.DatastoreVersionAlreadyExists,
"A datastore version with the name 'test_new_vr' already exists",
self.version_controller.create, self.req, body, self.tenant_id)
@patch.object(remote, 'create_nova_client')
def test_fail_image_not_found_version_create(self, mock_nova_client):
mock_nova_client.return_value.images.get = Mock(
side_effect=nova_exceptions.NotFound(404,
"Image id not found image-id"
))
body = {"version": {
"datastore_name": "test_ds",
"name": "test_vr",
"datastore_manager": "mysql",
"image": "image-id",
"packages": "test-pkg",
"active": True,
"default": True}}
self.assertRaisesRegexp(
exception.ImageNotFound,
"Image image-id cannot be found.",
self.version_controller.create, self.req, body, self.tenant_id)
def test_version_delete(self):
output = self.version_controller.delete(self.req,
self.tenant_id,
self.ds_version1.id)
err_msg = ("Datastore version '%s' cannot be found." %
self.ds_version1.id)
self.assertEqual(202, output.status)
# Try to find deleted version, this should raise exception.
self.assertRaisesRegexp(
exception.DatastoreVersionNotFound,
err_msg, models.DatastoreVersion.load_by_uuid, self.ds_version1.id)
@patch.object(remote, 'create_nova_client')
def test_version_update(self, mock_client):
body = {"image": "c022f4dc-76ed-4e3f-a25e-33e031f43f8b"}
output = self.version_controller.edit(self.req, body,
self.tenant_id,
self.ds_version2.id)
self.assertEqual(202, output.status)
# Find the details of version updated and match the updated attribute.
test_ds_version = models.DatastoreVersion.load_by_uuid(
self.ds_version2.id)
self.assertEqual(body['image'], test_ds_version.image_id)
@patch.object(remote, 'create_nova_client')
def test_version_update_fail_image_not_found(self, mock_nova_client):
mock_nova_client.return_value.images.get = Mock(
side_effect=nova_exceptions.NotFound(404,
"Image id not found image-id"
))
body = {"image": "non-existent-image-id"}
self.assertRaisesRegexp(
exception.ImageNotFound,
"Image non-existent-image-id cannot be found.",
self.version_controller.edit, self.req, body,
self.tenant_id, self.ds_version2.id)
@patch.object(models.Datastore, 'load')
def test_version_index(self, mock_load):
output = self.version_controller.index(
self.req, self.tenant_id)
self.assertEqual(200, output.status)
def test_version_show(self):
output = self.version_controller.show(
self.req, self.tenant_id, self.ds_version2.id)
self.assertEqual(200, output.status)
self.assertEqual(self.ds_version2.id,
output._data['version']['id'])
self.assertEqual(self.ds_version2.name,
output._data['version']['name'])
self.assertEqual(self.ds_version2.datastore_id,
output._data['version']['datastore_id'])
self.assertEqual(self.ds_version2.datastore_name,
output._data['version']['datastore_name'])
self.assertEqual(self.ds_version2.manager,
output._data['version']['datastore_manager'])
self.assertEqual(self.ds_version2.image_id,
output._data['version']['image'])
self.assertEqual(self.ds_version2.packages.split(','),
output._data['version']['packages'])
self.assertEqual(self.ds_version2.active,
output._data['version']['active'])