summaryrefslogtreecommitdiff
path: root/trove
diff options
context:
space:
mode:
Diffstat (limited to 'trove')
-rw-r--r--trove/common/apischema.py3
-rw-r--r--trove/common/cfg.py26
-rw-r--r--trove/instance/models.py33
-rw-r--r--trove/instance/service.py4
-rw-r--r--trove/instance/views.py4
-rw-r--r--trove/quota/quota.py5
-rw-r--r--trove/taskmanager/models.py42
-rw-r--r--trove/tests/api/instances.py16
-rw-r--r--trove/tests/api/limits.py12
-rw-r--r--trove/tests/api/mgmt/instances.py15
-rw-r--r--trove/tests/config.py6
-rw-r--r--trove/tests/unittests/instance/test_instance_views.py1
-rw-r--r--trove/tests/unittests/taskmanager/test_models.py1
13 files changed, 111 insertions, 57 deletions
diff --git a/trove/common/apischema.py b/trove/common/apischema.py
index 518da734..82ac0460 100644
--- a/trove/common/apischema.py
+++ b/trove/common/apischema.py
@@ -188,8 +188,7 @@ instance = {
"properties": {
"instance": {
"type": "object",
- "required": ["name", "flavorRef",
- "volume" if CONF.trove_volume_support else None],
+ "required": ["name", "flavorRef"],
"additionalProperties": True,
"properties": {
"name": non_empty_string,
diff --git a/trove/common/cfg.py b/trove/common/cfg.py
index 0c198153..fff15230 100644
--- a/trove/common/cfg.py
+++ b/trove/common/cfg.py
@@ -313,6 +313,10 @@ mysql_opts = [
default='trove.guestagent.strategies.backup.mysql_impl'),
cfg.StrOpt('restore_namespace',
default='trove.guestagent.strategies.restore.mysql_impl'),
+ cfg.BoolOpt('volume_support',
+ default=True,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default='/dev/vdb'),
]
# Percona
@@ -344,6 +348,10 @@ percona_opts = [
default='trove.guestagent.strategies.backup.mysql_impl'),
cfg.StrOpt('restore_namespace',
default='trove.guestagent.strategies.restore.mysql_impl'),
+ cfg.BoolOpt('volume_support',
+ default=True,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default='/dev/vdb'),
]
# Redis
@@ -366,6 +374,10 @@ redis_opts = [
"volumes if volume support is enabled."),
cfg.IntOpt('usage_timeout', default=450,
help='Timeout to wait for a guest to become active.'),
+ cfg.BoolOpt('volume_support',
+ default=False,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default=None),
]
# Cassandra
@@ -388,6 +400,10 @@ cassandra_opts = [
"volumes if volume support is enabled."),
cfg.IntOpt('usage_timeout', default=600,
help='Timeout to wait for a guest to become active.'),
+ cfg.BoolOpt('volume_support',
+ default=True,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default='/dev/vdb'),
]
# Couchbase
@@ -420,7 +436,11 @@ couchbase_opts = [
cfg.StrOpt('backup_namespace',
default='trove.guestagent.strategies.backup.couchbase_impl'),
cfg.StrOpt('restore_namespace',
- default='trove.guestagent.strategies.restore.couchbase_impl')
+ default='trove.guestagent.strategies.restore.couchbase_impl'),
+ cfg.BoolOpt('volume_support',
+ default=True,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default='/dev/vdb'),
]
# MongoDB
@@ -443,6 +463,10 @@ mongodb_opts = [
"volumes if volume support is enabled."),
cfg.IntOpt('usage_timeout', default=450,
help='Timeout to wait for a guest to become active.'),
+ cfg.BoolOpt('volume_support',
+ default=True,
+ help='Whether to provision a cinder volume for datadir.'),
+ cfg.StrOpt('device_path', default='/dev/vdb'),
]
CONF = cfg.CONF
diff --git a/trove/instance/models.py b/trove/instance/models.py
index 4da31e8e..f532c307 100644
--- a/trove/instance/models.py
+++ b/trove/instance/models.py
@@ -335,6 +335,14 @@ class SimpleInstance(object):
return self.ds
@property
+ def volume_support(self):
+ return CONF.get(self.datastore_version.manager).volume_support
+
+ @property
+ def device_path(self):
+ return CONF.get(self.datastore_version.manager).device_path
+
+ @property
def root_password(self):
return self.root_pass
@@ -510,7 +518,7 @@ class BaseInstance(SimpleInstance):
task_api.API(self.context).delete_instance(self.id)
deltas = {'instances': -1}
- if CONF.trove_volume_support:
+ if self.volume_support:
deltas['volumes'] = -self.volume_size
return run_with_quotas(self.tenant_id,
deltas,
@@ -616,15 +624,17 @@ class Instance(BuiltInstance):
raise exception.FlavorNotFound(uuid=flavor_id)
deltas = {'instances': 1}
- if CONF.trove_volume_support:
+ volume_support = CONF.get(datastore_version.manager).volume_support
+ if volume_support:
validate_volume_size(volume_size)
deltas['volumes'] = volume_size
else:
if volume_size is not None:
raise exception.VolumeNotSupported()
- ephemeral_support = CONF.device_path
- if ephemeral_support and flavor.ephemeral == 0:
- raise exception.LocalStorageNotSpecified(flavor=flavor_id)
+ ephemeral_support = CONF.get(datastore_version.manager).device_path
+ if ephemeral_support:
+ if flavor.ephemeral == 0:
+ raise exception.LocalStorageNotSpecified(flavor=flavor_id)
if backup_id is not None:
backup_info = Backup.get_by_id(context, backup_id)
@@ -726,18 +736,21 @@ class Instance(BuiltInstance):
old_flavor = client.flavors.get(self.flavor_id)
new_flavor_size = new_flavor.ram
old_flavor_size = old_flavor.ram
- if CONF.trove_volume_support:
+ if self.volume_support:
if new_flavor.ephemeral != 0:
raise exception.LocalStorageNotSupported()
if new_flavor_size == old_flavor_size:
raise exception.CannotResizeToSameSize()
- elif CONF.device_path is not None:
+ elif self.device_path is not None:
# ephemeral support enabled
if new_flavor.ephemeral == 0:
raise exception.LocalStorageNotSpecified(flavor=new_flavor_id)
if (new_flavor_size == old_flavor_size and
new_flavor.ephemeral == new_flavor.ephemeral):
raise exception.CannotResizeToSameSize()
+ elif new_flavor_size == old_flavor_size:
+ # uses local storage
+ raise exception.CannotResizeToSameSize()
# Set the task to RESIZING and begin the async call before returning.
self.update_db(task_status=InstanceTasks.RESIZING)
@@ -749,9 +762,6 @@ class Instance(BuiltInstance):
def _resize_resources():
self.validate_can_perform_action()
LOG.info("Resizing volume of instance %s..." % self.id)
- if not self.volume_size:
- raise exception.BadRequest(_("Instance %s has no volume.")
- % self.id)
old_size = self.volume_size
if int(new_size) <= old_size:
raise exception.BadRequest(_("The new volume 'size' must be "
@@ -761,6 +771,9 @@ class Instance(BuiltInstance):
self.update_db(task_status=InstanceTasks.RESIZING)
task_api.API(self.context).resize_volume(new_size, self.id)
+ if not self.volume_size:
+ raise exception.BadRequest(_("Instance %s has no volume.")
+ % self.id)
new_size_l = long(new_size)
validate_volume_size(new_size_l)
return run_with_quotas(self.tenant_id,
diff --git a/trove/instance/service.py b/trove/instance/service.py
index 64cae223..9428ac12 100644
--- a/trove/instance/service.py
+++ b/trove/instance/service.py
@@ -39,10 +39,6 @@ class InstanceController(wsgi.Controller):
"""Controller for instance functionality."""
schemas = apischema.instance.copy()
- if not CONF.trove_volume_support:
- # see instance.models.create for further validation around this
- LOG.info("Removing volume attributes from schema")
- schemas['create']['properties']['instance']['required'].pop()
@classmethod
def get_action_schema(cls, body, action_schema):
diff --git a/trove/instance/views.py b/trove/instance/views.py
index 55634272..57e9d91c 100644
--- a/trove/instance/views.py
+++ b/trove/instance/views.py
@@ -39,7 +39,7 @@ class InstanceView(object):
"datastore": {"type": self.instance.datastore.name,
"version": self.instance.datastore_version.name},
}
- if CONF.trove_volume_support:
+ if self.instance.volume_support:
instance_dict['volume'] = {'size': self.instance.volume_size}
if self.instance.hostname:
@@ -88,7 +88,7 @@ class InstanceDetailView(InstanceView):
if (isinstance(self.instance, models.DetailInstance) and
self.instance.volume_used):
used = self.instance.volume_used
- if CONF.trove_volume_support:
+ if self.instance.volume_support:
result['instance']['volume']['used'] = used
else:
# either ephemeral or root partition
diff --git a/trove/quota/quota.py b/trove/quota/quota.py
index 59bc072f..b9ec3bb5 100644
--- a/trove/quota/quota.py
+++ b/trove/quota/quota.py
@@ -312,9 +312,8 @@ QUOTAS = QuotaEngine()
''' Define all kind of resources here '''
resources = [Resource(Resource.INSTANCES, 'max_instances_per_user'),
- Resource(Resource.BACKUPS, 'max_backups_per_user')]
-if CONF.trove_volume_support:
- resources.append(Resource(Resource.VOLUMES, 'max_volumes_per_user'))
+ Resource(Resource.BACKUPS, 'max_backups_per_user'),
+ Resource(Resource.VOLUMES, 'max_volumes_per_user')]
QUOTAS.register_resources(resources)
diff --git a/trove/taskmanager/models.py b/trove/taskmanager/models.py
index f6a261dd..055c8919 100644
--- a/trove/taskmanager/models.py
+++ b/trove/taskmanager/models.py
@@ -118,7 +118,7 @@ class NotifyMixin(object):
'user_id': self.context.user,
}
- if CONF.trove_volume_support:
+ if CONF.get(self.datastore_version.manager).volume_support:
payload.update({
'volume_size': self.volume_size,
'nova_volume_id': self.volume_id
@@ -365,7 +365,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
err = inst_models.InstanceTasks.BUILDING_ERROR_SERVER
self._log_and_raise(e, msg, err)
- device_path = CONF.device_path
+ device_path = self.device_path
mount_point = CONF.get(datastore_manager).mount_point
volume_info = {'device_path': device_path, 'mount_point': mount_point}
LOG.debug("end _create_server_volume for id: %s" % self.id)
@@ -395,7 +395,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
ifaces, ports = self._build_heat_nics(nics)
template_obj = template.load_heat_template(datastore_manager)
heat_template_unicode = template_obj.render(
- volume_support=CONF.trove_volume_support,
+ volume_support=self.volume_support,
ifaces=ifaces, ports=ports,
tcp_rules=tcp_rules_mapping_list,
udp_rules=udp_ports_mapping_list,
@@ -438,7 +438,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
raise TroveError("Heat Resource Provisioning Failed.")
instance_id = resource.physical_resource_id
- if CONF.trove_volume_support:
+ if self.volume_support:
resource = client.resources.get(stack.id, 'DataVolume')
if resource.resource_status != HEAT_RESOURCE_SUCCESSFUL_STATE:
raise TroveError("Heat Resource Provisioning Failed.")
@@ -469,7 +469,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
err = inst_models.InstanceTasks.BUILDING_ERROR_SERVER
self._log_and_raise(e, msg, err)
- device_path = CONF.device_path
+ device_path = self.device_path
mount_point = CONF.get(datastore_manager).mount_point
volume_info = {'device_path': device_path, 'mount_point': mount_point}
@@ -504,7 +504,9 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
def _build_volume_info(self, datastore_manager, volume_size=None):
volume_info = None
- volume_support = CONF.trove_volume_support
+ volume_support = self.volume_support
+ device_path = self.device_path
+ mount_point = CONF.get(datastore_manager).mount_point
LOG.debug("trove volume support = %s" % volume_support)
if volume_support:
try:
@@ -515,13 +517,12 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
err = inst_models.InstanceTasks.BUILDING_ERROR_VOLUME
self._log_and_raise(e, msg, err)
else:
- LOG.debug("device_path = %s" % CONF.device_path)
- LOG.debug("mount_point = %s" %
- CONF.get(datastore_manager).mount_point)
+ LOG.debug("device_path = %s" % device_path)
+ LOG.debug("mount_point = %s" % mount_point)
volume_info = {
'block_device': None,
- 'device_path': CONF.device_path,
- 'mount_point': CONF.get(datastore_manager).mount_point,
+ 'device_path': device_path,
+ 'mount_point': mount_point,
'volumes': None,
}
return volume_info
@@ -570,7 +571,7 @@ class FreshInstanceTasks(FreshInstance, NotifyMixin, ConfigurationMixin):
LOG.debug("block_device = %s" % block_device)
LOG.debug("volume = %s" % created_volumes)
- device_path = CONF.device_path
+ device_path = self.device_path
mount_point = CONF.get(datastore_manager).mount_point
LOG.debug("device_path = %s" % device_path)
LOG.debug("mount_point = %s" % mount_point)
@@ -1021,6 +1022,9 @@ class ResizeVolumeAction(object):
self.instance.datastore_version.manager).mount_point
return mount_point
+ def get_device_path(self):
+ return self.instance.device_path
+
def _fail(self, orig_func):
LOG.exception(_("%(func)s encountered an error when attempting to "
"resize the volume for instance %(id)s. Setting service "
@@ -1066,7 +1070,8 @@ class ResizeVolumeAction(object):
LOG.debug("Unmounting the volume on instance %(id)s" % {
'id': self.instance.id})
mount_point = self.get_mount_point()
- self.instance.guest.unmount_volume(device_path=CONF.device_path,
+ device_path = self.get_device_path()
+ self.instance.guest.unmount_volume(device_path=device_path,
mount_point=mount_point)
LOG.debug("Successfully unmounted the volume %(vol_id)s for "
"instance %(id)s" % {'vol_id': self.instance.volume_id,
@@ -1094,11 +1099,12 @@ class ResizeVolumeAction(object):
@try_recover
def _attach_volume(self):
+ device_path = self.get_device_path()
LOG.debug("Attach volume %(vol_id)s to instance %(id)s at "
"%(dev)s" % {'vol_id': self.instance.volume_id,
- 'id': self.instance.id, 'dev': CONF.device_path})
+ 'id': self.instance.id, 'dev': device_path})
self.instance.nova_client.volumes.create_server_volume(
- self.instance.server.id, self.instance.volume_id, CONF.device_path)
+ self.instance.server.id, self.instance.volume_id, device_path)
def volume_in_use():
volume = self.instance.volume_client.volumes.get(
@@ -1117,7 +1123,8 @@ class ResizeVolumeAction(object):
LOG.debug("Resizing the filesystem for instance %(id)s" % {
'id': self.instance.id})
mount_point = self.get_mount_point()
- self.instance.guest.resize_fs(device_path=CONF.device_path,
+ device_path = self.get_device_path()
+ self.instance.guest.resize_fs(device_path=device_path,
mount_point=mount_point)
LOG.debug("Successfully resized volume %(vol_id)s filesystem for "
"instance %(id)s" % {'vol_id': self.instance.volume_id,
@@ -1128,7 +1135,8 @@ class ResizeVolumeAction(object):
LOG.debug("Mount the volume on instance %(id)s" % {
'id': self.instance.id})
mount_point = self.get_mount_point()
- self.instance.guest.mount_volume(device_path=CONF.device_path,
+ device_path = self.get_device_path()
+ self.instance.guest.mount_volume(device_path=device_path,
mount_point=mount_point)
LOG.debug("Successfully mounted the volume %(vol_id)s on instance "
"%(id)s" % {'vol_id': self.instance.volume_id,
diff --git a/trove/tests/api/instances.py b/trove/tests/api/instances.py
index cf72a237..4e241d09 100644
--- a/trove/tests/api/instances.py
+++ b/trove/tests/api/instances.py
@@ -238,9 +238,8 @@ class CreateInstanceQuotaTest(unittest.TestCase):
self.test_info.dbaas_datastore = CONFIG.dbaas_datastore
def tearDown(self):
- quota_dict = {'instances': CONFIG.trove_max_instances_per_user}
- if VOLUME_SUPPORT:
- quota_dict['volumes'] = CONFIG.trove_max_volumes_per_user
+ quota_dict = {'instances': CONFIG.trove_max_instances_per_user,
+ 'volumes': CONFIG.trove_max_volumes_per_user}
dbaas_admin.quota.update(self.test_info.user.tenant_id,
quota_dict)
@@ -410,6 +409,17 @@ class CreateInstanceFail(object):
volume, databases)
assert_equal(501, dbaas.last_http_code)
+ def test_create_failure_with_volume_size_and_disabled_for_datastore(self):
+ instance_name = "instance-failure-volume-size_and_volume_disabled"
+ databases = []
+ datastore = 'redis'
+ assert_equal(CONFIG.get(datastore, 'redis')['volume_support'], False)
+ volume = {'size': 2}
+ assert_raises(exceptions.HTTPNotImplemented, dbaas.instances.create,
+ instance_name, instance_info.dbaas_flavor_href,
+ volume, databases, datastore=datastore)
+ assert_equal(501, dbaas.last_http_code)
+
@test(enabled=EPHEMERAL_SUPPORT)
def test_create_failure_with_no_ephemeral_flavor(self):
instance_name = "instance-failure-with-no-ephemeral-flavor"
diff --git a/trove/tests/api/limits.py b/trove/tests/api/limits.py
index 0765b8cc..3ff56a86 100644
--- a/trove/tests/api/limits.py
+++ b/trove/tests/api/limits.py
@@ -27,7 +27,6 @@ from trove.tests.util import create_dbaas_client
from troveclient.compat import exceptions
from datetime import datetime
from trove.tests.util.users import Users
-from trove.tests.config import CONFIG
GROUP = "dbaas.api.limits"
DEFAULT_RATE = 200
@@ -93,8 +92,7 @@ class Limits(object):
assert_equal(abs_limits.verb, "ABSOLUTE")
assert_equal(int(abs_limits.max_instances), DEFAULT_MAX_INSTANCES)
assert_equal(int(abs_limits.max_backups), DEFAULT_MAX_BACKUPS)
- if CONFIG.trove_volume_support:
- assert_equal(int(abs_limits.max_volumes), DEFAULT_MAX_VOLUMES)
+ assert_equal(int(abs_limits.max_volumes), DEFAULT_MAX_VOLUMES)
for k in d:
assert_equal(d[k].verb, k)
@@ -116,8 +114,7 @@ class Limits(object):
assert_equal(int(abs_limits.max_instances), DEFAULT_MAX_INSTANCES)
assert_equal(int(abs_limits.max_backups), DEFAULT_MAX_BACKUPS)
- if CONFIG.trove_volume_support:
- assert_equal(int(abs_limits.max_volumes), DEFAULT_MAX_VOLUMES)
+ assert_equal(int(abs_limits.max_volumes), DEFAULT_MAX_VOLUMES)
assert_equal(get.verb, "GET")
assert_equal(get.unit, "MINUTE")
assert_true(int(get.remaining) <= DEFAULT_RATE - 5)
@@ -146,9 +143,8 @@ class Limits(object):
DEFAULT_MAX_INSTANCES)
assert_equal(int(abs_limits.max_backups),
DEFAULT_MAX_BACKUPS)
- if CONFIG.trove_volume_support:
- assert_equal(int(abs_limits.max_volumes),
- DEFAULT_MAX_VOLUMES)
+ assert_equal(int(abs_limits.max_volumes),
+ DEFAULT_MAX_VOLUMES)
except exceptions.OverLimit:
encountered = True
diff --git a/trove/tests/api/mgmt/instances.py b/trove/tests/api/mgmt/instances.py
index e39fa036..aac5e91b 100644
--- a/trove/tests/api/mgmt/instances.py
+++ b/trove/tests/api/mgmt/instances.py
@@ -81,6 +81,8 @@ def mgmt_instance_get():
# a global.
id = instance_info.id
api_instance = mgmt.show(id)
+ datastore = getattr(api_instance, 'datastore')
+ datastore_type = datastore.get('type')
# Print out all fields for extra info if the test fails.
for name in dir(api_instance):
@@ -102,7 +104,8 @@ def mgmt_instance_get():
instance.has_field('tenant_id', basestring)
instance.has_field('updated', basestring)
# Can be None if no volume is given on this instance.
- if CONFIG.trove_volume_support:
+ volume_support = CONFIG.get(datastore_type, 'mysql')['volume_support']
+ if volume_support:
instance.has_field('volume', dict, volume_check)
else:
instance.has_field('volume', None)
@@ -126,7 +129,7 @@ def mgmt_instance_get():
server.has_element("status", basestring)
server.has_element("tenant_id", basestring)
- if (CONFIG.trove_volume_support and
+ if (volume_support and
CONFIG.trove_main_instance_has_volume):
with CollectionCheck("volume", api_instance.volume) as volume:
volume.has_element("attachments", list)
@@ -151,9 +154,11 @@ class WhenMgmtInstanceGetIsCalledButServerIsNotReady(object):
# Fake volume will fail if the size is 13.
# TODO(tim.simpson): This would be a lot nicer looking if we used a
# traditional mock framework.
- body = None
- if CONFIG.trove_volume_support:
- body = {'size': 13}
+ datastore = {'type': 'mysql', 'version': '5.5'}
+ body = {'datastore': datastore}
+ vol_support = CONFIG.get(datastore['type'], 'mysql')['volume_support']
+ if vol_support:
+ body.update({'size': 13})
response = self.client.instances.create(
'test_SERVER_ERROR',
instance_info.dbaas_flavor_href,
diff --git a/trove/tests/config.py b/trove/tests/config.py
index fb501d4d..c07b5e80 100644
--- a/trove/tests/config.py
+++ b/trove/tests/config.py
@@ -116,8 +116,10 @@ class TestConfig(object):
"key_buffer_size",
"connect_timeout"
]
- }
- }
+ },
+ "volume_support": True,
+ },
+ "redis": {"volume_support": False},
}
self._frozen_values = FrozenDict(self._values)
self._users = None
diff --git a/trove/tests/unittests/instance/test_instance_views.py b/trove/tests/unittests/instance/test_instance_views.py
index 371a28a7..1189c23c 100644
--- a/trove/tests/unittests/instance/test_instance_views.py
+++ b/trove/tests/unittests/instance/test_instance_views.py
@@ -53,6 +53,7 @@ class InstanceDetailViewTest(TestCase):
self.instance.updated = 'Now'
self.instance.datastore_version = Mock()
self.instance.datastore_version.name = 'mysql_test_version'
+ self.instance.datastore_version.manager = 'mysql'
self.instance.hostname = 'test.trove.com'
self.ip = "1.2.3.4"
self.instance.addresses = {"private": [{"addr": self.ip}]}
diff --git a/trove/tests/unittests/taskmanager/test_models.py b/trove/tests/unittests/taskmanager/test_models.py
index 5def6b12..41e6d7f1 100644
--- a/trove/tests/unittests/taskmanager/test_models.py
+++ b/trove/tests/unittests/taskmanager/test_models.py
@@ -359,6 +359,7 @@ class ResizeVolumeTest(testtools.TestCase):
class FakeGroup():
def __init__(self):
self.mount_point = 'var/lib/mysql'
+ self.device_path = '/dev/vdb'
taskmanager_models.CONF.get = Mock(return_value=FakeGroup())
def tearDown(self):