Resize replicas (volume) together with primary

When resizing volume for an instance which is the primary of a
replication, cluster, Trove also resizes the volume for all the replicas
automatically.

Change-Id: I2e719772fe7abc719255ea2a705d9ec342aced2a
This commit is contained in:
Lingxian Kong 2020-07-27 22:02:23 +12:00
parent be6f8565f5
commit 8e48d757e6
4 changed files with 39 additions and 19 deletions

View File

@ -82,6 +82,9 @@ size. A valid volume size is an integer value in gigabytes (GB).
You cannot increase the volume to a size that is larger than the You cannot increase the volume to a size that is larger than the
API volume size limit. API volume size limit.
For replication cluster, resizing volume of the primary will also resize
replicas automatically.
Normal response codes: 202 Normal response codes: 202
Request Request

View File

@ -0,0 +1,4 @@
---
features:
- When resizing volume for an instance which is the primary of a replication
cluster, Trove also resizes the volume for all the replicas automatically.

View File

@ -1353,28 +1353,41 @@ class Instance(BuiltInstance):
new_flavor) new_flavor)
def resize_volume(self, new_size): def resize_volume(self, new_size):
def _resize_resources(): """Resize instance volume.
self.validate_can_perform_action()
LOG.info("Resizing volume of instance %s.", self.id)
if self.db_info.cluster_id is not None:
raise exception.ClusterInstanceOperationNotSupported()
old_size = self.volume_size
if int(new_size) <= old_size:
raise exception.BadRequest(_("The new volume 'size' must be "
"larger than the current volume "
"size of '%s'.") % old_size)
# Set the task to Resizing before sending off to the taskmanager
self.update_db(task_status=InstanceTasks.RESIZING)
task_api.API(self.context).resize_volume(new_size, self.id)
If the instance is primary in a replication cluster, volumes of all the
replicas are also resized.
"""
def _resize_resources(instance):
LOG.info("Resizing volume of instance %s.", instance.id)
instance.update_db(task_status=InstanceTasks.RESIZING)
task_api.API(self.context).resize_volume(new_size, instance.id)
new_size_l = int(new_size)
if self.db_info.cluster_id is not None:
raise exception.ClusterInstanceOperationNotSupported()
if not self.volume_size: if not self.volume_size:
raise exception.BadRequest(_("Instance %s has no volume.") raise exception.BadRequest(_("Instance %s has no volume.")
% self.id) % self.id)
new_size_l = int(new_size) if new_size_l <= self.volume_size:
raise exception.BadRequest(_("The new volume 'size' must be "
"larger than the current volume "
"size of '%s'.") % self.volume_size)
validate_volume_size(new_size_l) validate_volume_size(new_size_l)
return run_with_quotas(self.tenant_id, self.validate_can_perform_action()
{'volumes': new_size_l - self.volume_size},
_resize_resources) instances = [self]
for dbinfo in self.slaves:
replica = Instance.load(self.context, dbinfo.id, needs_server=True)
replica.validate_can_perform_action()
instances.append(replica)
for instance in instances:
run_with_quotas(
self.tenant_id, {'volumes': new_size_l - self.volume_size},
_resize_resources, instance)
def reboot(self): def reboot(self):
LOG.info("Rebooting instance %s.", self.id) LOG.info("Rebooting instance %s.", self.id)

View File

@ -356,13 +356,13 @@ resources = [Resource(Resource.INSTANCES, 'max_instances_per_tenant'),
QUOTAS.register_resources(resources) QUOTAS.register_resources(resources)
def run_with_quotas(tenant_id, deltas, f): def run_with_quotas(tenant_id, deltas, f, *args, **kwargs):
"""Quota wrapper.""" """Quota wrapper."""
reservations = QUOTAS.reserve(tenant_id, **deltas) reservations = QUOTAS.reserve(tenant_id, **deltas)
result = None result = None
try: try:
result = f() result = f(*args, **kwargs)
except Exception: except Exception:
QUOTAS.rollback(reservations) QUOTAS.rollback(reservations)
raise raise