diff --git a/troveclient/base.py b/troveclient/base.py index 9b594056..41bd7a82 100644 --- a/troveclient/base.py +++ b/troveclient/base.py @@ -175,12 +175,15 @@ class Manager(utils.HookableMixin): def _create(self, url, body, response_key, return_raw=False, **kwargs): self.run_hooks('modify_body_for_create', body, **kwargs) resp, body = self.api.client.post(url, body=body) - if return_raw: - return body[response_key] + if body: + if return_raw: + return body[response_key] - with self.completion_cache('human_id', self.resource_class, mode="a"): - with self.completion_cache('uuid', self.resource_class, mode="a"): - return self.resource_class(self, body[response_key]) + with self.completion_cache('human_id', self.resource_class, + mode="a"): + with self.completion_cache('uuid', self.resource_class, + mode="a"): + return self.resource_class(self, body[response_key]) def _delete(self, url): resp, body = self.api.client.delete(url) diff --git a/troveclient/compat/client.py b/troveclient/compat/client.py index eaa0bebb..d59cf819 100644 --- a/troveclient/compat/client.py +++ b/troveclient/compat/client.py @@ -355,6 +355,7 @@ class Dbaas(object): self.configuration_parameters = config_parameters self.metadata = metadata.Metadata(self) self.mgmt_configs = management.MgmtConfigurationParameters(self) + self.mgmt_datastore_versions = management.MgmtDatastoreVersions(self) class Mgmt(object): def __init__(self, dbaas): @@ -362,6 +363,7 @@ class Dbaas(object): self.hosts = dbaas.hosts self.accounts = dbaas.accounts self.storage = dbaas.storage + self.datastore_version = dbaas.mgmt_datastore_versions self.mgmt = Mgmt(self) diff --git a/troveclient/tests/test_management.py b/troveclient/tests/test_management.py index 7c0a77b5..62f9f8da 100644 --- a/troveclient/tests/test_management.py +++ b/troveclient/tests/test_management.py @@ -183,3 +183,98 @@ class MgmtFlavorsTest(testtools.TestCase): self.assertEqual(1024, b["flavor"]["ram"]) self.assertEqual(2, b["flavor"]["vcpu"]) self.assertEqual(1, b["flavor"]["flavor_id"]) + + +class MgmtDatastoreVersionsTest(testtools.TestCase): + + def setUp(self): + super(MgmtDatastoreVersionsTest, self).setUp() + self.orig__init = management.MgmtDatastoreVersions.__init__ + management.MgmtDatastoreVersions.__init__ = mock.Mock( + return_value=None) + self.ds_version = management.MgmtDatastoreVersions() + self.ds_version.api = mock.Mock() + self.ds_version.api.client = mock.Mock() + self.ds_version.resource_class = mock.Mock(return_value="ds-version-1") + self.orig_base_getid = base.getid + base.getid = mock.Mock(return_value="ds-version1") + + def tearDown(self): + super(MgmtDatastoreVersionsTest, self).tearDown() + management.MgmtDatastoreVersions.__init__ = self.orig__init + base.getid = self.orig_base_getid + + def _get_mock_method(self): + self._resp = mock.Mock() + self._body = None + self._url = None + + def side_effect_func(url, body=None): + self._body = body + self._url = url + return (self._resp, body) + + return mock.Mock(side_effect=side_effect_func) + + def test_create(self): + def side_effect_func(path, body, *kw): + return path, body + + self.ds_version._create = mock.Mock(side_effect=side_effect_func) + p, b, = self.ds_version.create( + "ds-version1", "mysql", "mysql", "image-id", + ["mysql-server-5.5"], "true", "true") + self.assertEqual("/mgmt/datastore-versions", p) + self.assertEqual("ds-version1", b["version"]["name"]) + self.assertEqual("mysql", b["version"]["datastore_name"]) + self.assertEqual("mysql", b["version"]["datastore_manager"]) + self.assertEqual("image-id", b["version"]["image"]) + self.assertEqual(["mysql-server-5.5"], b["version"]["packages"]) + self.assertTrue(b["version"]["active"]) + self.assertTrue(b["version"]["default"]) + + def test_get(self): + def side_effect_func(path, ins): + return path, ins + self.ds_version._get = mock.Mock(side_effect=side_effect_func) + p, i = self.ds_version.get('ds-version-1') + self.assertEqual(('/mgmt/datastore-versions/ds-version-1', 'version'), + (p, i)) + + def test_list(self): + page_mock = mock.Mock() + self.ds_version._paginated = page_mock + self.ds_version.list() + page_mock.assert_called_with('/mgmt/datastore-versions', + 'versions', None, None) + self.ds_version.list(limit=10, marker="foo") + page_mock.assert_called_with('/mgmt/datastore-versions', + 'versions', 10, "foo") + + def test_delete(self): + resp = mock.Mock() + resp.status_code = 202 + self.ds_version.api.client.delete = mock.Mock( + return_value=(resp, None) + ) + self.ds_version.delete('ds-version-1') + self.assertEqual(1, self.ds_version.api.client.delete.call_count) + self.ds_version.api.client.delete.assert_called_with( + '/mgmt/datastore-versions/ds-version-1') + + resp.status_code = 400 + self.assertRaises(Exception, self.ds_version.delete, 'ds-version-2') + self.assertEqual(2, self.ds_version.api.client.delete.call_count) + self.ds_version.api.client.delete.assert_called_with( + '/mgmt/datastore-versions/ds-version-2') + + def test_edit(self): + self.ds_version.api.client.patch = self._get_mock_method() + self._resp.status_code = 202 + self.ds_version.edit('ds-version-1', image="new-image-id") + self.assertEqual('/mgmt/datastore-versions/ds-version-1', self._url) + self.assertDictEqual({"image": "new-image-id"}, self._body) + + self._resp.status_code = 400 + self.assertRaises(Exception, self.ds_version.edit, 'ds-version-1', + "new-mgr", "non-existent-image") diff --git a/troveclient/v1/management.py b/troveclient/v1/management.py index ddb06dcb..4b572051 100644 --- a/troveclient/v1/management.py +++ b/troveclient/v1/management.py @@ -14,10 +14,13 @@ # License for the specific language governing permissions and limitations # under the License. +import json + from troveclient import base from troveclient import common from troveclient.v1 import clusters from troveclient.v1 import configurations +from troveclient.v1 import datastores from troveclient.v1 import flavors from troveclient.v1 import instances @@ -252,3 +255,57 @@ class MgmtConfigurationParameters(configurations.ConfigurationParameters): "parameters/%(parameter_name)s" % output) resp, body = self.api.client.delete(url) common.check_for_exceptions(resp, body, url) + + +class MgmtDatastoreVersions(base.ManagerWithFind): + """Manage :class:`DatastoreVersion` resources.""" + resource_class = datastores.DatastoreVersion + + def list(self, limit=None, marker=None): + """List all datastore versions.""" + return self._paginated("/mgmt/datastore-versions", "versions", + limit, marker) + + def get(self, datastore_version_id): + """Get details of a datastore version.""" + return self._get("/mgmt/datastore-versions/%s" % datastore_version_id, + "version") + + def create(self, name, datastore_name, datastore_manager, image, + packages=[], active='true', default='false'): + """Create a new datastore version.""" + body = {"version": { + "name": name, + "datastore_name": datastore_name, + "datastore_manager": datastore_manager, + "image": image, + "packages": packages, + "active": json.loads(active), + "default": json.loads(default) + }} + + return self._create("/mgmt/datastore-versions", body, None, True) + + def edit(self, datastore_version_id, datastore_manager=None, image=None, + packages=[], active=None, default=None): + """Update a datastore-version.""" + body = {} + if datastore_manager is not None: + body['datastore_manager'] = datastore_manager + if image: + body['image'] = image + if packages: + body['packages'] = packages + if active is not None: + body['active'] = json.loads(active) + if default is not None: + body['default'] = json.loads(default) + url = ("/mgmt/datastore-versions/%s" % datastore_version_id) + resp, body = self.api.client.patch(url, body=body) + common.check_for_exceptions(resp, body, url) + + def delete(self, datastore_version_id): + """Delete a datastore version.""" + url = ("/mgmt/datastore-versions/%s" % datastore_version_id) + resp, body = self.api.client.delete(url) + common.check_for_exceptions(resp, body, url)