Revert "Remove flavor API"
Story: 2008341
Task: 41242
This reverts commit 27cf71299e
.
Change-Id: I036a0423263b1a0332415c6403647ae82c9e34c4
This commit is contained in:
parent
dd371f0454
commit
c04e299b1d
|
@ -63,6 +63,8 @@ openstack.database.v1 =
|
||||||
database_db_create = troveclient.osc.v1.databases:CreateDatabase
|
database_db_create = troveclient.osc.v1.databases:CreateDatabase
|
||||||
database_db_delete = troveclient.osc.v1.databases:DeleteDatabase
|
database_db_delete = troveclient.osc.v1.databases:DeleteDatabase
|
||||||
database_db_list = troveclient.osc.v1.databases:ListDatabases
|
database_db_list = troveclient.osc.v1.databases:ListDatabases
|
||||||
|
database_flavor_list = troveclient.osc.v1.database_flavors:ListDatabaseFlavors
|
||||||
|
database_flavor_show = troveclient.osc.v1.database_flavors:ShowDatabaseFlavor
|
||||||
database_instance_create = troveclient.osc.v1.database_instances:CreateDatabaseInstance
|
database_instance_create = troveclient.osc.v1.database_instances:CreateDatabaseInstance
|
||||||
database_instance_delete = troveclient.osc.v1.database_instances:DeleteDatabaseInstance
|
database_instance_delete = troveclient.osc.v1.database_instances:DeleteDatabaseInstance
|
||||||
database_instance_force_delete = troveclient.osc.v1.database_instances:ForceDeleteDatabaseInstance
|
database_instance_force_delete = troveclient.osc.v1.database_instances:ForceDeleteDatabaseInstance
|
||||||
|
|
|
@ -21,9 +21,11 @@ from troveclient.v1.accounts import Accounts # noqa
|
||||||
from troveclient.v1.databases import Databases # noqa
|
from troveclient.v1.databases import Databases # noqa
|
||||||
from troveclient.v1.diagnostics import DiagnosticsInterrogator # noqa
|
from troveclient.v1.diagnostics import DiagnosticsInterrogator # noqa
|
||||||
from troveclient.v1.diagnostics import HwInfoInterrogator # noqa
|
from troveclient.v1.diagnostics import HwInfoInterrogator # noqa
|
||||||
|
from troveclient.v1.flavors import Flavors # noqa
|
||||||
from troveclient.v1.hosts import Hosts # noqa
|
from troveclient.v1.hosts import Hosts # noqa
|
||||||
from troveclient.v1.instances import Instances # noqa
|
from troveclient.v1.instances import Instances # noqa
|
||||||
from troveclient.v1.management import Management # noqa
|
from troveclient.v1.management import Management # noqa
|
||||||
|
from troveclient.v1.management import MgmtFlavors # noqa
|
||||||
from troveclient.v1.management import RootHistory # noqa
|
from troveclient.v1.management import RootHistory # noqa
|
||||||
from troveclient.v1.root import Root # noqa
|
from troveclient.v1.root import Root # noqa
|
||||||
from troveclient.v1.storage import StorageInfo # noqa
|
from troveclient.v1.storage import StorageInfo # noqa
|
||||||
|
|
|
@ -129,6 +129,16 @@ class InstanceCommands(common.AuthedCommandsBase):
|
||||||
self._pretty_print(self.dbaas.instances.configuration, self.id)
|
self._pretty_print(self.dbaas.instances.configuration, self.id)
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorsCommands(common.AuthedCommandsBase):
|
||||||
|
"""Command for listing Flavors."""
|
||||||
|
|
||||||
|
params = []
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
"""List the available flavors."""
|
||||||
|
self._pretty_list(self.dbaas.flavors.list)
|
||||||
|
|
||||||
|
|
||||||
class DatabaseCommands(common.AuthedCommandsBase):
|
class DatabaseCommands(common.AuthedCommandsBase):
|
||||||
"""Database CRUD operations on an instance."""
|
"""Database CRUD operations on an instance."""
|
||||||
|
|
||||||
|
@ -426,6 +436,7 @@ class MetadataCommands(common.AuthedCommandsBase):
|
||||||
COMMANDS = {
|
COMMANDS = {
|
||||||
'auth': common.Auth,
|
'auth': common.Auth,
|
||||||
'instance': InstanceCommands,
|
'instance': InstanceCommands,
|
||||||
|
'flavor': FlavorsCommands,
|
||||||
'database': DatabaseCommands,
|
'database': DatabaseCommands,
|
||||||
'limit': LimitsCommands,
|
'limit': LimitsCommands,
|
||||||
'backup': BackupsCommands,
|
'backup': BackupsCommands,
|
||||||
|
|
|
@ -309,6 +309,7 @@ class Dbaas(object):
|
||||||
from troveclient.v1 import databases
|
from troveclient.v1 import databases
|
||||||
from troveclient.v1 import datastores
|
from troveclient.v1 import datastores
|
||||||
from troveclient.v1 import diagnostics
|
from troveclient.v1 import diagnostics
|
||||||
|
from troveclient.v1 import flavors
|
||||||
from troveclient.v1 import hosts
|
from troveclient.v1 import hosts
|
||||||
from troveclient.v1 import instances
|
from troveclient.v1 import instances
|
||||||
from troveclient.v1 import limits
|
from troveclient.v1 import limits
|
||||||
|
@ -330,6 +331,7 @@ class Dbaas(object):
|
||||||
region_name=region_name)
|
region_name=region_name)
|
||||||
self.versions = versions.Versions(self)
|
self.versions = versions.Versions(self)
|
||||||
self.databases = databases.Databases(self)
|
self.databases = databases.Databases(self)
|
||||||
|
self.flavors = flavors.Flavors(self)
|
||||||
self.instances = instances.Instances(self)
|
self.instances = instances.Instances(self)
|
||||||
self.limits = limits.Limits(self)
|
self.limits = limits.Limits(self)
|
||||||
self.users = users.Users(self)
|
self.users = users.Users(self)
|
||||||
|
@ -347,6 +349,7 @@ class Dbaas(object):
|
||||||
self.storage = storage.StorageInfo(self)
|
self.storage = storage.StorageInfo(self)
|
||||||
self.management = management.Management(self)
|
self.management = management.Management(self)
|
||||||
self.mgmt_cluster = management.MgmtClusters(self)
|
self.mgmt_cluster = management.MgmtClusters(self)
|
||||||
|
self.mgmt_flavor = management.MgmtFlavors(self)
|
||||||
self.accounts = accounts.Accounts(self)
|
self.accounts = accounts.Accounts(self)
|
||||||
self.diagnostics = diagnostics.DiagnosticsInterrogator(self)
|
self.diagnostics = diagnostics.DiagnosticsInterrogator(self)
|
||||||
self.hwinfo = diagnostics.HwInfoInterrogator(self)
|
self.hwinfo = diagnostics.HwInfoInterrogator(self)
|
||||||
|
|
|
@ -181,6 +181,31 @@ class StorageCommands(common.AuthedCommandsBase):
|
||||||
self._pretty_list(self.dbaas.storage.index)
|
self._pretty_list(self.dbaas.storage.index)
|
||||||
|
|
||||||
|
|
||||||
|
class FlavorsCommands(common.AuthedCommandsBase):
|
||||||
|
"""Commands for managing Flavors."""
|
||||||
|
|
||||||
|
params = [
|
||||||
|
'name',
|
||||||
|
'ram',
|
||||||
|
'disk',
|
||||||
|
'vcpus',
|
||||||
|
'flavor_id',
|
||||||
|
'ephemeral',
|
||||||
|
'swap',
|
||||||
|
'rxtx_factor',
|
||||||
|
'service_type'
|
||||||
|
]
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
"""Create a new flavor."""
|
||||||
|
self._require('name', 'ram', 'disk', 'vcpus',
|
||||||
|
'flavor_id', 'service_type')
|
||||||
|
self._pretty_print(self.dbaas.mgmt_flavor.create, self.name,
|
||||||
|
self.ram, self.disk, self.vcpus, self.flavor_id,
|
||||||
|
self.ephemeral, self.swap, self.rxtx_factor,
|
||||||
|
self.service_type)
|
||||||
|
|
||||||
|
|
||||||
def config_options(oparser):
|
def config_options(oparser):
|
||||||
oparser.add_option("-u", "--url", default="http://localhost:5000/v1.1",
|
oparser.add_option("-u", "--url", default="http://localhost:5000/v1.1",
|
||||||
help="Auth API endpoint URL with port and version. \
|
help="Auth API endpoint URL with port and version. \
|
||||||
|
@ -194,6 +219,7 @@ COMMANDS = {
|
||||||
'root': RootCommands,
|
'root': RootCommands,
|
||||||
'storage': StorageCommands,
|
'storage': StorageCommands,
|
||||||
'quota': QuotaCommands,
|
'quota': QuotaCommands,
|
||||||
|
'flavor': FlavorsCommands,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""Database v1 Flavors action implementations"""
|
||||||
|
|
||||||
|
from osc_lib.command import command
|
||||||
|
from osc_lib import utils
|
||||||
|
import six
|
||||||
|
|
||||||
|
from troveclient import exceptions
|
||||||
|
from troveclient.i18n import _
|
||||||
|
|
||||||
|
|
||||||
|
def set_attributes_for_print_detail(flavor):
|
||||||
|
info = flavor._info.copy()
|
||||||
|
# Get rid of those ugly links
|
||||||
|
if info.get('links'):
|
||||||
|
del(info['links'])
|
||||||
|
|
||||||
|
# Fallback to str_id for flavors, where necessary
|
||||||
|
if hasattr(flavor, 'str_id'):
|
||||||
|
info['id'] = flavor.id
|
||||||
|
del(info['str_id'])
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
class ListDatabaseFlavors(command.Lister):
|
||||||
|
|
||||||
|
_description = _("List database flavors")
|
||||||
|
columns = ['ID', 'Name', 'RAM', 'vCPUs', 'Disk', 'Ephemeral']
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ListDatabaseFlavors, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'--datastore-type',
|
||||||
|
dest='datastore_type',
|
||||||
|
metavar='<datastore-type>',
|
||||||
|
help=_('Type of the datastore. For eg: mysql.')
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--datastore-version-id',
|
||||||
|
dest='datastore_version_id',
|
||||||
|
metavar='<datastore-version-id>',
|
||||||
|
help=_('ID of the datastore version.')
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
db_flavors = self.app.client_manager.database.flavors
|
||||||
|
if parsed_args.datastore_type and parsed_args.datastore_version_id:
|
||||||
|
flavors = db_flavors.list_datastore_version_associated_flavors(
|
||||||
|
datastore=parsed_args.datastore_type,
|
||||||
|
version_id=parsed_args.datastore_version_id)
|
||||||
|
elif (not parsed_args.datastore_type and not
|
||||||
|
parsed_args.datastore_version_id):
|
||||||
|
flavors = db_flavors.list()
|
||||||
|
else:
|
||||||
|
raise exceptions.MissingArgs(['datastore-type',
|
||||||
|
'datastore-version-id'])
|
||||||
|
|
||||||
|
# Fallback to str_id where necessary.
|
||||||
|
_flavors = []
|
||||||
|
for f in flavors:
|
||||||
|
if not f.id and hasattr(f, 'str_id'):
|
||||||
|
f.id = f.str_id
|
||||||
|
_flavors.append(utils.get_item_properties(f, self.columns))
|
||||||
|
|
||||||
|
return self.columns, _flavors
|
||||||
|
|
||||||
|
|
||||||
|
class ShowDatabaseFlavor(command.ShowOne):
|
||||||
|
_description = _("Shows details of a database flavor")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ShowDatabaseFlavor, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
'flavor',
|
||||||
|
metavar='<flavor>',
|
||||||
|
help=_('ID or name of the flavor'),
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
db_flavors = self.app.client_manager.database.flavors
|
||||||
|
flavor = utils.find_resource(db_flavors,
|
||||||
|
parsed_args.flavor)
|
||||||
|
flavor = set_attributes_for_print_detail(flavor)
|
||||||
|
return zip(*sorted(six.iteritems(flavor)))
|
|
@ -244,7 +244,8 @@ class CreateDatabaseInstance(command.ShowOne):
|
||||||
'--flavor',
|
'--flavor',
|
||||||
metavar='<flavor>',
|
metavar='<flavor>',
|
||||||
type=str,
|
type=str,
|
||||||
help=_("A flavor ID."),
|
help=_("Flavor to create the instance (name or ID). Flavor is not "
|
||||||
|
"required when creating replica instances."),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--size',
|
'--size',
|
||||||
|
@ -373,8 +374,16 @@ class CreateDatabaseInstance(command.ShowOne):
|
||||||
db_instances = database.instances
|
db_instances = database.instances
|
||||||
|
|
||||||
if not parsed_args.replica_of and not parsed_args.flavor:
|
if not parsed_args.replica_of and not parsed_args.flavor:
|
||||||
raise exceptions.CommandError(
|
raise exceptions.CommandError(_("Please specify a flavor"))
|
||||||
_("Please specify a flavor"))
|
|
||||||
|
if parsed_args.replica_of and parsed_args.flavor:
|
||||||
|
print("Warning: Flavor is ignored for creating replica.")
|
||||||
|
|
||||||
|
if not parsed_args.replica_of:
|
||||||
|
flavor_id = osc_utils.find_resource(
|
||||||
|
database.flavors, parsed_args.flavor).id
|
||||||
|
else:
|
||||||
|
flavor_id = None
|
||||||
|
|
||||||
volume = None
|
volume = None
|
||||||
if parsed_args.size is not None and parsed_args.size <= 0:
|
if parsed_args.size is not None and parsed_args.size <= 0:
|
||||||
|
@ -441,7 +450,7 @@ class CreateDatabaseInstance(command.ShowOne):
|
||||||
|
|
||||||
instance = db_instances.create(
|
instance = db_instances.create(
|
||||||
parsed_args.name,
|
parsed_args.name,
|
||||||
flavor_id=parsed_args.flavor,
|
flavor_id=flavor_id,
|
||||||
volume=volume,
|
volume=volume,
|
||||||
databases=databases,
|
databases=databases,
|
||||||
users=users,
|
users=users,
|
||||||
|
|
|
@ -20,6 +20,7 @@ from troveclient.v1 import clusters
|
||||||
from troveclient.v1 import configurations
|
from troveclient.v1 import configurations
|
||||||
from troveclient.v1 import databases
|
from troveclient.v1 import databases
|
||||||
from troveclient.v1 import datastores
|
from troveclient.v1 import datastores
|
||||||
|
from troveclient.v1 import flavors
|
||||||
from troveclient.v1 import instances
|
from troveclient.v1 import instances
|
||||||
from troveclient.v1 import limits
|
from troveclient.v1 import limits
|
||||||
from troveclient.v1 import modules
|
from troveclient.v1 import modules
|
||||||
|
@ -33,6 +34,13 @@ class TestDatabasev1(utils.TestCommand):
|
||||||
self.app.client_manager.database = mock.MagicMock()
|
self.app.client_manager.database = mock.MagicMock()
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFlavors(object):
|
||||||
|
fake_flavors = fakes.FakeHTTPClient().get_flavors()[2]['flavors']
|
||||||
|
|
||||||
|
def get_flavors_1(self):
|
||||||
|
return flavors.Flavor(None, self.fake_flavors[0])
|
||||||
|
|
||||||
|
|
||||||
class FakeBackups(object):
|
class FakeBackups(object):
|
||||||
fake_backups = fakes.FakeHTTPClient().get_backups()[2]['backups']
|
fake_backups = fakes.FakeHTTPClient().get_backups()[2]['backups']
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# 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 troveclient.osc.v1 import database_flavors
|
||||||
|
from troveclient.tests.osc.v1 import fakes
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlavors(fakes.TestDatabasev1):
|
||||||
|
fake_flavors = fakes.FakeFlavors()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFlavors, self).setUp()
|
||||||
|
self.mock_client = self.app.client_manager.database
|
||||||
|
self.flavor_client = self.app.client_manager.database.flavors
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlavorList(TestFlavors):
|
||||||
|
columns = database_flavors.ListDatabaseFlavors.columns
|
||||||
|
values = (1, 'm1.tiny', 512, '', '', '')
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFlavorList, self).setUp()
|
||||||
|
self.cmd = database_flavors.ListDatabaseFlavors(self.app, None)
|
||||||
|
self.data = [self.fake_flavors.get_flavors_1()]
|
||||||
|
self.flavor_client.list.return_value = self.data
|
||||||
|
self.flavor_client.list_datastore_version_associated_flavors. \
|
||||||
|
return_value = self.data
|
||||||
|
|
||||||
|
def test_flavor_list_defaults(self):
|
||||||
|
parsed_args = self.check_parser(self.cmd, [], [])
|
||||||
|
columns, values = self.cmd.take_action(parsed_args)
|
||||||
|
self.flavor_client.list.assert_called_once_with()
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual([self.values], values)
|
||||||
|
|
||||||
|
def test_flavor_list_with_optional_args(self):
|
||||||
|
args = ['--datastore-type', 'mysql',
|
||||||
|
'--datastore-version-id', '5.6']
|
||||||
|
parsed_args = self.check_parser(self.cmd, args, [])
|
||||||
|
list_flavor_dict = {'datastore': 'mysql',
|
||||||
|
'version_id': '5.6'}
|
||||||
|
columns, values = self.cmd.take_action(parsed_args)
|
||||||
|
self.flavor_client.list_datastore_version_associated_flavors. \
|
||||||
|
assert_called_once_with(**list_flavor_dict)
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual([self.values], values)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFlavorShow(TestFlavors):
|
||||||
|
|
||||||
|
values = (1, 'm1.tiny', 512)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFlavorShow, self).setUp()
|
||||||
|
self.cmd = database_flavors.ShowDatabaseFlavor(self.app, None)
|
||||||
|
self.data = self.fake_flavors.get_flavors_1()
|
||||||
|
self.flavor_client.get.return_value = self.data
|
||||||
|
self.columns = (
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'ram',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_flavor_show_defaults(self):
|
||||||
|
args = ['m1.tiny']
|
||||||
|
parsed_args = self.check_parser(self.cmd, args, [])
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.values, data)
|
|
@ -222,7 +222,6 @@ class TestDatabaseInstanceCreate(TestInstances):
|
||||||
|
|
||||||
@mock.patch.object(utils, 'find_resource')
|
@mock.patch.object(utils, 'find_resource')
|
||||||
def test_instance_create(self, mock_find):
|
def test_instance_create(self, mock_find):
|
||||||
mock_find.id.side_effect = ['test', 'mod_id']
|
|
||||||
args = ['test-name', '--flavor', '103',
|
args = ['test-name', '--flavor', '103',
|
||||||
'--size', '1',
|
'--size', '1',
|
||||||
'--databases', 'db1', 'db2',
|
'--databases', 'db1', 'db2',
|
||||||
|
@ -256,7 +255,8 @@ class TestDatabaseInstanceCreate(TestInstances):
|
||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertEqual(self.values, data)
|
self.assertEqual(self.values, data)
|
||||||
|
|
||||||
def test_instance_create_without_allowed_cidrs(self):
|
@mock.patch.object(utils, 'find_resource')
|
||||||
|
def test_instance_create_without_allowed_cidrs(self, mock_find):
|
||||||
resp = {
|
resp = {
|
||||||
"id": "a1fea1cf-18ad-48ab-bdfd-fce99a4b834e",
|
"id": "a1fea1cf-18ad-48ab-bdfd-fce99a4b834e",
|
||||||
"name": "test-mysql",
|
"name": "test-mysql",
|
||||||
|
@ -338,7 +338,10 @@ class TestDatabaseInstanceCreate(TestInstances):
|
||||||
self.assertEqual(expected_columns, columns)
|
self.assertEqual(expected_columns, columns)
|
||||||
self.assertEqual(expected_values, data)
|
self.assertEqual(expected_values, data)
|
||||||
|
|
||||||
def test_instance_create_nic_param(self):
|
@mock.patch.object(utils, 'find_resource')
|
||||||
|
def test_instance_create_nic_param(self, mock_find):
|
||||||
|
fake_id = self.random_uuid()
|
||||||
|
mock_find.return_value.id = fake_id
|
||||||
args = [
|
args = [
|
||||||
'test-mysql',
|
'test-mysql',
|
||||||
'--flavor', 'a48ea749-7ee3-4003-8aae-eb4e79773e2d',
|
'--flavor', 'a48ea749-7ee3-4003-8aae-eb4e79773e2d',
|
||||||
|
@ -352,7 +355,7 @@ class TestDatabaseInstanceCreate(TestInstances):
|
||||||
|
|
||||||
self.instance_client.create.assert_called_once_with(
|
self.instance_client.create.assert_called_once_with(
|
||||||
'test-mysql',
|
'test-mysql',
|
||||||
flavor_id='a48ea749-7ee3-4003-8aae-eb4e79773e2d',
|
flavor_id=fake_id,
|
||||||
volume={"size": 1, "type": None},
|
volume={"size": 1, "type": None},
|
||||||
databases=[],
|
databases=[],
|
||||||
users=[],
|
users=[],
|
||||||
|
|
|
@ -165,6 +165,38 @@ class ManagementTest(testtools.TestCase):
|
||||||
self.assertEqual({'reset-task-status': {}}, self.body_)
|
self.assertEqual({'reset-task-status': {}}, self.body_)
|
||||||
|
|
||||||
|
|
||||||
|
class MgmtFlavorsTest(testtools.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(MgmtFlavorsTest, self).setUp()
|
||||||
|
self.orig__init = management.MgmtFlavors.__init__
|
||||||
|
management.MgmtFlavors.__init__ = mock.Mock(return_value=None)
|
||||||
|
self.flavors = management.MgmtFlavors()
|
||||||
|
self.flavors.api = mock.Mock()
|
||||||
|
self.flavors.api.client = mock.Mock()
|
||||||
|
self.flavors.resource_class = mock.Mock(return_value="flavor-1")
|
||||||
|
self.orig_base_getid = base.getid
|
||||||
|
base.getid = mock.Mock(return_value="flavor1")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(MgmtFlavorsTest, self).tearDown()
|
||||||
|
management.MgmtFlavors.__init__ = self.orig__init
|
||||||
|
base.getid = self.orig_base_getid
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
def side_effect_func(path, body, inst):
|
||||||
|
return path, body, inst
|
||||||
|
|
||||||
|
self.flavors._create = mock.Mock(side_effect=side_effect_func)
|
||||||
|
p, b, i = self.flavors.create("test-name", 1024, 30, 2, 1)
|
||||||
|
self.assertEqual("/mgmt/flavors", p)
|
||||||
|
self.assertEqual("flavor", i)
|
||||||
|
self.assertEqual("test-name", b["flavor"]["name"])
|
||||||
|
self.assertEqual(1024, b["flavor"]["ram"])
|
||||||
|
self.assertEqual(2, b["flavor"]["vcpu"])
|
||||||
|
self.assertEqual(1, b["flavor"]["flavor_id"])
|
||||||
|
|
||||||
|
|
||||||
class MgmtDatastoreVersionsTest(testtools.TestCase):
|
class MgmtDatastoreVersionsTest(testtools.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -21,6 +21,7 @@ from troveclient.v1 import clusters
|
||||||
from troveclient.v1 import configurations
|
from troveclient.v1 import configurations
|
||||||
from troveclient.v1 import databases
|
from troveclient.v1 import databases
|
||||||
from troveclient.v1 import datastores
|
from troveclient.v1 import datastores
|
||||||
|
from troveclient.v1 import flavors
|
||||||
from troveclient.v1 import instances
|
from troveclient.v1 import instances
|
||||||
from troveclient.v1 import limits
|
from troveclient.v1 import limits
|
||||||
from troveclient.v1 import management
|
from troveclient.v1 import management
|
||||||
|
@ -64,6 +65,7 @@ class Client(object):
|
||||||
# self.limits = limits.LimitsManager(self)
|
# self.limits = limits.LimitsManager(self)
|
||||||
|
|
||||||
# extensions
|
# extensions
|
||||||
|
self.flavors = flavors.Flavors(self)
|
||||||
self.volume_types = volume_types.VolumeTypes(self)
|
self.volume_types = volume_types.VolumeTypes(self)
|
||||||
self.users = users.Users(self)
|
self.users = users.Users(self)
|
||||||
self.databases = databases.Databases(self)
|
self.databases = databases.Databases(self)
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Copyright 2011 OpenStack Foundation
|
||||||
|
# Copyright 2013 Rackspace Hosting
|
||||||
|
# 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 troveclient import base
|
||||||
|
|
||||||
|
|
||||||
|
class Flavor(base.Resource):
|
||||||
|
"""A Flavor is an Instance type, specifying other things, like RAM size."""
|
||||||
|
|
||||||
|
def __init__(self, manager, info, loaded=False):
|
||||||
|
super(Flavor, self).__init__(manager, info, loaded)
|
||||||
|
if self.id is None and self.str_id is not None:
|
||||||
|
self.id = self.str_id
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Flavor: %s>" % self.name
|
||||||
|
|
||||||
|
|
||||||
|
class Flavors(base.ManagerWithFind):
|
||||||
|
"""Manage :class:`Flavor` resources."""
|
||||||
|
resource_class = Flavor
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
"""Get a list of all flavors.
|
||||||
|
:rtype: list of :class:`Flavor`.
|
||||||
|
"""
|
||||||
|
return self._list("/flavors", "flavors")
|
||||||
|
|
||||||
|
def list_datastore_version_associated_flavors(self, datastore,
|
||||||
|
version_id):
|
||||||
|
"""Get a list of all flavors for the specified datastore type
|
||||||
|
and datastore version .
|
||||||
|
:rtype: list of :class:`Flavor`.
|
||||||
|
"""
|
||||||
|
return self._list("/datastores/%s/versions/%s/flavors" %
|
||||||
|
(datastore, version_id),
|
||||||
|
"flavors")
|
||||||
|
|
||||||
|
def get(self, flavor):
|
||||||
|
"""Get a specific flavor.
|
||||||
|
|
||||||
|
:rtype: :class:`Flavor`
|
||||||
|
"""
|
||||||
|
return self._get("/flavors/%s" % base.getid(flavor),
|
||||||
|
"flavor")
|
|
@ -21,6 +21,7 @@ from troveclient import common
|
||||||
from troveclient.v1 import clusters
|
from troveclient.v1 import clusters
|
||||||
from troveclient.v1 import configurations
|
from troveclient.v1 import configurations
|
||||||
from troveclient.v1 import datastores
|
from troveclient.v1 import datastores
|
||||||
|
from troveclient.v1 import flavors
|
||||||
from troveclient.v1 import instances
|
from troveclient.v1 import instances
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,6 +150,44 @@ class MgmtClusters(base.ManagerWithFind):
|
||||||
self._action(cluster_id, body)
|
self._action(cluster_id, body)
|
||||||
|
|
||||||
|
|
||||||
|
class MgmtFlavors(base.ManagerWithFind):
|
||||||
|
"""Manage :class:`Flavor` resources."""
|
||||||
|
resource_class = flavors.Flavor
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Flavors Manager at %s>" % id(self)
|
||||||
|
|
||||||
|
# Appease the abc gods
|
||||||
|
def list(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create(self, name, ram, disk, vcpus,
|
||||||
|
flavorid="auto", ephemeral=None, swap=None, rxtx_factor=None,
|
||||||
|
service_type=None):
|
||||||
|
"""Create a new flavor."""
|
||||||
|
body = {"flavor": {
|
||||||
|
"flavor_id": flavorid,
|
||||||
|
"name": name,
|
||||||
|
"ram": ram,
|
||||||
|
"disk": disk,
|
||||||
|
"vcpu": vcpus,
|
||||||
|
"ephemeral": 0,
|
||||||
|
"swap": 0,
|
||||||
|
"rxtx_factor": "1.0",
|
||||||
|
"is_public": "True"
|
||||||
|
}}
|
||||||
|
if ephemeral:
|
||||||
|
body["flavor"]["ephemeral"] = ephemeral
|
||||||
|
if swap:
|
||||||
|
body["flavor"]["swap"] = swap
|
||||||
|
if rxtx_factor:
|
||||||
|
body["flavor"]["rxtx_factor"] = rxtx_factor
|
||||||
|
if service_type:
|
||||||
|
body["flavor"]["service_type"] = service_type
|
||||||
|
|
||||||
|
return self._create("/mgmt/flavors", body, "flavor")
|
||||||
|
|
||||||
|
|
||||||
class MgmtConfigurationParameters(configurations.ConfigurationParameters):
|
class MgmtConfigurationParameters(configurations.ConfigurationParameters):
|
||||||
def create(self, version, name, restart_required, data_type,
|
def create(self, version, name, restart_required, data_type,
|
||||||
max_size=None, min_size=None):
|
max_size=None, min_size=None):
|
||||||
|
|
|
@ -187,6 +187,11 @@ def _find_cluster(cs, cluster):
|
||||||
return utils.find_resource(cs.clusters, cluster)
|
return utils.find_resource(cs.clusters, cluster)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_flavor(cs, flavor):
|
||||||
|
"""Get a flavor by ID."""
|
||||||
|
return utils.find_resource(cs.flavors, flavor)
|
||||||
|
|
||||||
|
|
||||||
def _find_volume_type(cs, volume_type):
|
def _find_volume_type(cs, volume_type):
|
||||||
"""Get a volume type by ID."""
|
"""Get a volume type by ID."""
|
||||||
return utils.find_resource(cs.volume_types, volume_type)
|
return utils.find_resource(cs.volume_types, volume_type)
|
||||||
|
@ -217,6 +222,46 @@ def _find_configuration(cs, configuration):
|
||||||
return utils.find_resource(cs.configurations, configuration)
|
return utils.find_resource(cs.configurations, configuration)
|
||||||
|
|
||||||
|
|
||||||
|
# Flavor related calls
|
||||||
|
@utils.arg('--datastore_type', metavar='<datastore_type>',
|
||||||
|
default=None,
|
||||||
|
help=_('Type of the datastore. For eg: mysql.'))
|
||||||
|
@utils.arg("--datastore_version_id", metavar="<datastore_version_id>",
|
||||||
|
default=None, help=_("ID of the datastore version."))
|
||||||
|
@utils.service_type('database')
|
||||||
|
def do_flavor_list(cs, args):
|
||||||
|
"""Lists available flavors."""
|
||||||
|
if args.datastore_type and args.datastore_version_id:
|
||||||
|
flavors = cs.flavors.list_datastore_version_associated_flavors(
|
||||||
|
args.datastore_type, args.datastore_version_id)
|
||||||
|
elif not args.datastore_type and not args.datastore_version_id:
|
||||||
|
flavors = cs.flavors.list()
|
||||||
|
else:
|
||||||
|
raise exceptions.MissingArgs(['datastore_type',
|
||||||
|
'datastore_version_id'])
|
||||||
|
|
||||||
|
# Fallback to str_id where necessary.
|
||||||
|
_flavors = []
|
||||||
|
for f in flavors:
|
||||||
|
if not f.id and hasattr(f, 'str_id'):
|
||||||
|
f.id = f.str_id
|
||||||
|
_flavors.append(f)
|
||||||
|
|
||||||
|
utils.print_list(_flavors, ['id', 'name', 'ram', 'vcpus', 'disk',
|
||||||
|
'ephemeral'],
|
||||||
|
labels={'ram': 'RAM', 'vcpus': 'vCPUs', 'disk': 'Disk'},
|
||||||
|
order_by='ram')
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('flavor', metavar='<flavor>', type=str,
|
||||||
|
help=_('ID or name of the flavor.'))
|
||||||
|
@utils.service_type('database')
|
||||||
|
def do_flavor_show(cs, args):
|
||||||
|
"""Shows details of a flavor."""
|
||||||
|
flavor = _find_flavor(cs, args.flavor)
|
||||||
|
_print_object(flavor)
|
||||||
|
|
||||||
|
|
||||||
# Volume type related calls
|
# Volume type related calls
|
||||||
@utils.arg('--datastore_type', metavar='<datastore_type>',
|
@utils.arg('--datastore_type', metavar='<datastore_type>',
|
||||||
default=None,
|
default=None,
|
||||||
|
@ -508,7 +553,7 @@ def do_update(cs, args):
|
||||||
@utils.arg('flavor',
|
@utils.arg('flavor',
|
||||||
metavar='<flavor>',
|
metavar='<flavor>',
|
||||||
type=str,
|
type=str,
|
||||||
help=_('A flavor ID.'))
|
help=_('A flavor name or ID.'))
|
||||||
@utils.arg('--databases', metavar='<database>',
|
@utils.arg('--databases', metavar='<database>',
|
||||||
help=_('Optional list of databases.'),
|
help=_('Optional list of databases.'),
|
||||||
nargs="+", default=[])
|
nargs="+", default=[])
|
||||||
|
@ -576,7 +621,7 @@ def do_update(cs, args):
|
||||||
@utils.service_type('database')
|
@utils.service_type('database')
|
||||||
def do_create(cs, args):
|
def do_create(cs, args):
|
||||||
"""Creates a new instance."""
|
"""Creates a new instance."""
|
||||||
flavor_id = args.flavor
|
flavor_id = _find_flavor(cs, args.flavor).id
|
||||||
volume = None
|
volume = None
|
||||||
if args.size is not None and args.size <= 0:
|
if args.size is not None and args.size <= 0:
|
||||||
raise exceptions.ValidationError(
|
raise exceptions.ValidationError(
|
||||||
|
@ -639,7 +684,8 @@ def _validate_nic_info(nic_info, nic_str):
|
||||||
|
|
||||||
|
|
||||||
def _get_flavor(cs, opts_str):
|
def _get_flavor(cs, opts_str):
|
||||||
flavor_id, opts_str = _strip_option(opts_str, 'flavor', True)
|
flavor_name, opts_str = _strip_option(opts_str, 'flavor', True)
|
||||||
|
flavor_id = _find_flavor(cs, flavor_name).id
|
||||||
return str(flavor_id), opts_str
|
return str(flavor_id), opts_str
|
||||||
|
|
||||||
|
|
||||||
|
@ -881,12 +927,12 @@ def do_cluster_create(cs, args):
|
||||||
@utils.arg('flavor',
|
@utils.arg('flavor',
|
||||||
metavar='<flavor>',
|
metavar='<flavor>',
|
||||||
type=str,
|
type=str,
|
||||||
help=_('New flavor ID for the instance.'))
|
help=_('New flavor of the instance.'))
|
||||||
@utils.service_type('database')
|
@utils.service_type('database')
|
||||||
def do_resize_instance(cs, args):
|
def do_resize_instance(cs, args):
|
||||||
"""Resizes an instance with a new flavor."""
|
"""Resizes an instance with a new flavor."""
|
||||||
instance = _find_instance(cs, args.instance)
|
instance = _find_instance(cs, args.instance)
|
||||||
flavor_id = args.flavor
|
flavor_id = _find_flavor(cs, args.flavor).id
|
||||||
cs.instances.resize_instance(instance, flavor_id)
|
cs.instances.resize_instance(instance, flavor_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue