diff --git a/trove_dashboard/api/trove.py b/trove_dashboard/api/trove.py index 44ba17f..80625ef 100644 --- a/trove_dashboard/api/trove.py +++ b/trove_dashboard/api/trove.py @@ -121,11 +121,13 @@ def instance_delete(request, instance_id): def instance_create(request, name, volume, flavor, databases=None, users=None, restore_point=None, nics=None, datastore=None, datastore_version=None, - replica_of=None): + replica_of=None, volume_type=None): # TODO(dklyle): adding conditional to support trove without volume # support for now until API supports checking for volume support if volume > 0: volume_params = {'size': volume} + if volume_type: + volume_params['type'] = volume_type else: volume_params = None return troveclient(request).instances.create( diff --git a/trove_dashboard/content/databases/tests.py b/trove_dashboard/content/databases/tests.py index 44f126c..8d174f5 100644 --- a/trove_dashboard/content/databases/tests.py +++ b/trove_dashboard/content/databases/tests.py @@ -129,6 +129,7 @@ class DatabaseTests(test.TestCase): api.trove: ('flavor_list', 'backup_list', 'datastore_list', 'datastore_version_list', 'instance_list'), + dash_api.cinder: ('volume_type_list',), dash_api.neutron: ('network_list',)}) def test_launch_instance(self): api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn( @@ -144,6 +145,8 @@ class DatabaseTests(test.TestCase): api.trove.datastore_version_list(IsA(http.HttpRequest), IsA(str)).\ MultipleTimes().AndReturn(self.datastore_versions.list()) + dash_api.cinder.volume_type_list(IsA(http.HttpRequest)).AndReturn([]) + dash_api.neutron.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).AndReturn( @@ -192,6 +195,7 @@ class DatabaseTests(test.TestCase): api.trove: ('flavor_list', 'backup_list', 'instance_create', 'datastore_list', 'datastore_version_list', 'instance_list'), + dash_api.cinder: ('volume_type_list',), dash_api.neutron: ('network_list',)}) def test_create_simple_instance(self): api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn( @@ -211,6 +215,8 @@ class DatabaseTests(test.TestCase): api.trove.datastore_version_list(IsA(http.HttpRequest), IsA(str))\ .MultipleTimes().AndReturn(self.datastore_versions.list()) + dash_api.cinder.volume_type_list(IsA(http.HttpRequest)).AndReturn([]) + dash_api.neutron.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).AndReturn( @@ -234,7 +240,8 @@ class DatabaseTests(test.TestCase): restore_point=None, replica_of=None, users=None, - nics=nics).AndReturn(self.databases.first()) + nics=nics, + volume_type=None).AndReturn(self.databases.first()) self.mox.ReplayAll() post = { @@ -243,6 +250,7 @@ class DatabaseTests(test.TestCase): 'flavor': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'network': self.networks.first().id, 'datastore': 'mysql,5.5', + 'volume_type': 'no_type' } res = self.client.post(LAUNCH_URL, post) @@ -252,6 +260,7 @@ class DatabaseTests(test.TestCase): api.trove: ('flavor_list', 'backup_list', 'instance_create', 'datastore_list', 'datastore_version_list', 'instance_list'), + dash_api.cinder: ('volume_type_list',), dash_api.neutron: ('network_list',)}) def test_create_simple_instance_exception(self): trove_exception = self.exceptions.nova @@ -272,6 +281,8 @@ class DatabaseTests(test.TestCase): api.trove.datastore_version_list(IsA(http.HttpRequest), IsA(str))\ .MultipleTimes().AndReturn(self.datastore_versions.list()) + dash_api.cinder.volume_type_list(IsA(http.HttpRequest)).AndReturn([]) + dash_api.neutron.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).AndReturn( @@ -295,7 +306,8 @@ class DatabaseTests(test.TestCase): restore_point=None, replica_of=None, users=None, - nics=nics).AndRaise(trove_exception) + nics=nics, + volume_type=None).AndRaise(trove_exception) self.mox.ReplayAll() post = { @@ -304,6 +316,7 @@ class DatabaseTests(test.TestCase): 'flavor': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'network': self.networks.first().id, 'datastore': 'mysql,5.5', + 'volume_type': 'no_type' } res = self.client.post(LAUNCH_URL, post) @@ -939,6 +952,7 @@ class DatabaseTests(test.TestCase): api.trove: ('flavor_list', 'backup_list', 'instance_create', 'datastore_list', 'datastore_version_list', 'instance_list', 'instance_get'), + dash_api.cinder: ('volume_type_list',), dash_api.neutron: ('network_list',)}) def test_create_replica_instance(self): api.trove.flavor_list(IsA(http.HttpRequest)).AndReturn( @@ -957,6 +971,8 @@ class DatabaseTests(test.TestCase): IsA(str))\ .MultipleTimes().AndReturn(self.datastore_versions.list()) + dash_api.cinder.volume_type_list(IsA(http.HttpRequest)).AndReturn([]) + dash_api.neutron.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).\ @@ -983,7 +999,8 @@ class DatabaseTests(test.TestCase): restore_point=None, replica_of=self.databases.first().id, users=None, - nics=nics).AndReturn(self.databases.first()) + nics=nics, + volume_type=None).AndReturn(self.databases.first()) self.mox.ReplayAll() post = { @@ -993,7 +1010,8 @@ class DatabaseTests(test.TestCase): 'network': self.networks.first().id, 'datastore': 'mysql,5.5', 'initial_state': 'master', - 'master': self.databases.first().id + 'master': self.databases.first().id, + 'volume_type': 'no_type' } res = self.client.post(LAUNCH_URL, post) diff --git a/trove_dashboard/content/databases/workflows/create_instance.py b/trove_dashboard/content/databases/workflows/create_instance.py index 532bf3d..c4a72bf 100644 --- a/trove_dashboard/content/databases/workflows/create_instance.py +++ b/trove_dashboard/content/databases/workflows/create_instance.py @@ -39,6 +39,10 @@ class SetInstanceDetailsAction(workflows.Action): min_value=0, initial=1, help_text=_("Size of the volume in GB.")) + volume_type = forms.ChoiceField( + label=_("Volume Type"), + required=False, + help_text=_("Applicable only if the volume size is specified.")) datastore = forms.ChoiceField(label=_("Datastore"), help_text=_( "Type and version of datastore.")) @@ -70,6 +74,17 @@ class SetInstanceDetailsAction(workflows.Action): return instance_utils.sort_flavor_list(request, flavors) return [] + @memoized.memoized_method + def populate_volume_type_choices(self, request, context): + try: + volume_types = dash_api.cinder.volume_type_list(request) + return ([("no_type", _("No volume type"))] + + [(type.name, type.name) + for type in volume_types]) + except Exception: + LOG.exception("Exception while obtaining volume types list") + self._volume_types = [] + @memoized.memoized_method def datastores(self, request): try: @@ -124,7 +139,7 @@ TROVE_ADD_PERMS = TROVE_ADD_USER_PERMS + TROVE_ADD_DATABASE_PERMS class SetInstanceDetails(workflows.Step): action_class = SetInstanceDetailsAction - contributes = ("name", "volume", "flavor", "datastore") + contributes = ("name", "volume", "volume_type", "flavor", "datastore") class SetNetworkAction(workflows.Action): @@ -388,16 +403,23 @@ class LaunchInstance(workflows.Workflow): else: return None + def _get_volume_type(self, context): + volume_type = None + if context.get('volume_type') != 'no_type': + volume_type = context['volume_type'] + return volume_type + def handle(self, request, context): try: datastore = self.context['datastore'].split(',')[0] datastore_version = self.context['datastore'].split(',')[1] LOG.info("Launching database instance with parameters " - "{name=%s, volume=%s, flavor=%s, " + "{name=%s, volume=%s, volume_type=%s, flavor=%s, " "datastore=%s, datastore_version=%s, " "dbs=%s, users=%s, " "backups=%s, nics=%s, replica_of=%s}", - context['name'], context['volume'], context['flavor'], + context['name'], context['volume'], + self._get_volume_type(context), context['flavor'], datastore, datastore_version, self._get_databases(context), self._get_users(context), self._get_backup(context), self._get_nics(context), @@ -412,7 +434,9 @@ class LaunchInstance(workflows.Workflow): users=self._get_users(context), restore_point=self._get_backup(context), nics=self._get_nics(context), - replica_of=context.get('master')) + replica_of=context.get('master'), + volume_type=self._get_volume_type( + context)) return True except Exception: exceptions.handle(request)