Use vitastor-cli in the Cinder driver for modifications instead of direct etcd interaction
This commit is contained in:
+28
-230
@@ -291,6 +291,14 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
else:
|
else:
|
||||||
return (1 + resp['kvs'][0]['value'], resp['kvs'][0]['mod_revision'])
|
return (1 + resp['kvs'][0]['value'], resp['kvs'][0]['mod_revision'])
|
||||||
|
|
||||||
|
def _cli(self, descr, *args):
|
||||||
|
args = [ 'vitastor-cli', *args, *(self._vitastor_args()) ]
|
||||||
|
try:
|
||||||
|
self._execute(*args)
|
||||||
|
except processutils.ProcessExecutionError as exc:
|
||||||
|
LOG.error("Failed to "+descr+": "+exc)
|
||||||
|
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
||||||
|
|
||||||
def create_volume(self, volume):
|
def create_volume(self, volume):
|
||||||
"""Creates a logical volume."""
|
"""Creates a logical volume."""
|
||||||
|
|
||||||
@@ -302,7 +310,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
|
|
||||||
LOG.debug("creating volume '%s'", vol_name)
|
LOG.debug("creating volume '%s'", vol_name)
|
||||||
|
|
||||||
self._create_image(vol_name, { 'size': size })
|
self._cli('create volume', 'create', vol_name, '--size', size)
|
||||||
|
|
||||||
if volume.encryption_key_id:
|
if volume.encryption_key_id:
|
||||||
self._create_encrypted_volume(volume, volume.obj_context)
|
self._create_encrypted_volume(volume, volume.obj_context)
|
||||||
@@ -346,7 +354,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
if snap_name.find('@') >= 0 or snap_name.find('/') >= 0:
|
if snap_name.find('@') >= 0 or snap_name.find('/') >= 0:
|
||||||
raise exception.VolumeBackendAPIException(data = '@ and / are forbidden in volume and snapshot names')
|
raise exception.VolumeBackendAPIException(data = '@ and / are forbidden in volume and snapshot names')
|
||||||
self._create_snapshot(vol_name, vol_name+'@'+snap_name)
|
self._cli('create snapshot', 'snap-create', vol_name+'@'+snap_name)
|
||||||
|
|
||||||
def snapshot_revert_use_temp_snapshot(self):
|
def snapshot_revert_use_temp_snapshot(self):
|
||||||
"""Disable the use of a temporary snapshot on revert."""
|
"""Disable the use of a temporary snapshot on revert."""
|
||||||
@@ -359,21 +367,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
# Delete the image and recreate it from the snapshot
|
# Delete the image and recreate it from the snapshot
|
||||||
args = [ 'vitastor-cli', 'rm', vol_name, *(self._vitastor_args()) ]
|
self._cli('delete image', 'rm', vol_name)
|
||||||
try:
|
self._cli('recreate image', 'create', '--parent', vol_name+'@'+snap_name, vol_name)
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to delete image "+vol_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
args = [
|
|
||||||
'vitastor-cli', 'create', '--parent', vol_name+'@'+snap_name,
|
|
||||||
vol_name, *(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to recreate image "+vol_name+" from "+vol_name+"@"+snap_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
def delete_snapshot(self, snapshot):
|
def delete_snapshot(self, snapshot):
|
||||||
"""Deletes a snapshot."""
|
"""Deletes a snapshot."""
|
||||||
@@ -381,15 +376,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
vol_name = utils.convert_str(snapshot.volume_name)
|
vol_name = utils.convert_str(snapshot.volume_name)
|
||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
args = [
|
self._cli('remove snapshot', 'rm', vol_name+'@'+snap_name)
|
||||||
'vitastor-cli', 'rm', vol_name+'@'+snap_name,
|
|
||||||
*(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to remove snapshot "+vol_name+'@'+snap_name+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
def _child_count(self, parents):
|
def _child_count(self, parents):
|
||||||
children = 0
|
children = 0
|
||||||
@@ -427,13 +414,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
if src_vref.admin_metadata.get('readonly') == 'True':
|
if src_vref.admin_metadata.get('readonly') == 'True':
|
||||||
# source volume is a volume-image cache entry or other readonly volume
|
# source volume is a volume-image cache entry or other readonly volume
|
||||||
# clone without intermediate snapshot
|
# clone without intermediate snapshot
|
||||||
src = self._get_image(src_name)
|
self._cli('create clone', 'create', '--parent', src_name, '--size', size, dest_name)
|
||||||
LOG.debug("creating image '%s' from '%s'", dest_name, src_name)
|
|
||||||
new_cfg = self._create_image(dest_name, {
|
|
||||||
'size': size,
|
|
||||||
'parent_id': src['idx']['id'],
|
|
||||||
'parent_pool_id': src['idx']['pool_id'],
|
|
||||||
})
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
clone_snap = "%s@%s.clone_snap" % (src_name, dest_name)
|
clone_snap = "%s@%s.clone_snap" % (src_name, dest_name)
|
||||||
@@ -446,15 +427,12 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
clone_snap = dest_name
|
clone_snap = dest_name
|
||||||
make_img = False
|
make_img = False
|
||||||
|
|
||||||
LOG.debug("creating layer '%s' under '%s'", clone_snap, src_name)
|
LOG.debug("creating snapshot '%s'", clone_snap)
|
||||||
new_cfg = self._create_snapshot(src_name, clone_snap, True)
|
self._cli('create base snapshot', 'snap-create', '--allow-existing', '1', clone_snap)
|
||||||
|
|
||||||
if make_img:
|
if make_img:
|
||||||
# Then create a clone from it
|
# Then create a clone from it
|
||||||
new_cfg = self._create_image(dest_name, {
|
self._cli('create clone', 'create', '--parent', clone_snap, '--size', size, dest_name)
|
||||||
'size': size,
|
|
||||||
'parent_id': new_cfg['parent_id'],
|
|
||||||
'parent_pool_id': new_cfg['parent_pool_id'],
|
|
||||||
})
|
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
@@ -464,7 +442,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
snap_name = utils.convert_str(snapshot.name)
|
snap_name = utils.convert_str(snapshot.name)
|
||||||
|
|
||||||
snap = self._get_image('volume-'+snapshot.volume_id+'@'+snap_name)
|
src_snap = 'volume-'+snapshot.volume_id+'@'+snap_name
|
||||||
|
snap = self._get_image(src_snap)
|
||||||
if not snap:
|
if not snap:
|
||||||
raise exception.SnapshotNotFound(snapshot_id = snap_name)
|
raise exception.SnapshotNotFound(snapshot_id = snap_name)
|
||||||
snap_inode_id = int(resp['responses'][0]['kvs'][0]['value']['id'])
|
snap_inode_id = int(resp['responses'][0]['kvs'][0]['value']['id'])
|
||||||
@@ -473,12 +452,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
size = snap['cfg']['size']
|
size = snap['cfg']['size']
|
||||||
if int(volume.size):
|
if int(volume.size):
|
||||||
size = int(volume.size) * units.Gi
|
size = int(volume.size) * units.Gi
|
||||||
new_cfg = self._create_image(vol_name, {
|
|
||||||
'size': size,
|
|
||||||
'parent_id': snap['idx']['id'],
|
|
||||||
'parent_pool_id': snap['idx']['pool_id'],
|
|
||||||
})
|
|
||||||
|
|
||||||
|
self._cli('create clone', 'create', vol_name, '--size', size, '--parent', src_snap)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _vitastor_args(self):
|
def _vitastor_args(self):
|
||||||
@@ -505,49 +480,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""Deletes a logical volume."""
|
"""Deletes a logical volume."""
|
||||||
|
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
|
self._cli('delete volume', 'rm', '--matching', vol_name, vol_name+'@*', '--progress', '0')
|
||||||
# Find the volume and all its snapshots
|
|
||||||
range_end = b'index/image/' + vol_name.encode('utf-8')
|
|
||||||
range_end = range_end[0 : len(range_end)-1] + six.int2byte(range_end[len(range_end)-1] + 1)
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name, 'range_end': range_end } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
# already deleted
|
|
||||||
LOG.info("volume %s no longer exists in backend", vol_name)
|
|
||||||
return
|
|
||||||
layers = resp['responses'][0]['kvs']
|
|
||||||
layer_ids = {}
|
|
||||||
for kv in layers:
|
|
||||||
inode_id = int(kv['value']['id'])
|
|
||||||
pool_id = int(kv['value']['pool_id'])
|
|
||||||
inode_pool_id = (pool_id << 48) | (inode_id & 0xffffffffffff)
|
|
||||||
layer_ids[inode_pool_id] = True
|
|
||||||
|
|
||||||
# Check if the volume has clones and raise 'busy' if so
|
|
||||||
children = self._child_count(layer_ids)
|
|
||||||
if children > 0:
|
|
||||||
raise exception.VolumeIsBusy(volume_name = vol_name)
|
|
||||||
|
|
||||||
# Clear data
|
|
||||||
for kv in layers:
|
|
||||||
args = [
|
|
||||||
'vitastor-cli', 'rm-data', '--pool', str(kv['value']['pool_id']),
|
|
||||||
'--inode', str(kv['value']['id']), '--progress', '0',
|
|
||||||
*(self._vitastor_args())
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
self._execute(*args)
|
|
||||||
except processutils.ProcessExecutionError as exc:
|
|
||||||
LOG.error("Failed to remove layer "+kv['key']+": "+exc)
|
|
||||||
raise exception.VolumeBackendAPIException(data = exc.stderr)
|
|
||||||
|
|
||||||
# Delete all layers from etcd
|
|
||||||
requests = []
|
|
||||||
for kv in layers:
|
|
||||||
requests.append({ 'request_delete_range': { 'key': kv['key'] } })
|
|
||||||
requests.append({ 'request_delete_range': { 'key': 'config/inode/'+str(kv['value']['pool_id'])+'/'+str(kv['value']['id']) } })
|
|
||||||
self._etcd_txn({ 'success': requests })
|
|
||||||
|
|
||||||
def retype(self, context, volume, new_type, diff, host):
|
def retype(self, context, volume, new_type, diff, host):
|
||||||
"""Change extra type specifications for a volume."""
|
"""Change extra type specifications for a volume."""
|
||||||
@@ -567,98 +500,6 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""Removes an export for a logical volume."""
|
"""Removes an export for a logical volume."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _create_image(self, vol_name, cfg):
|
|
||||||
pool_s = str(self.cfg['pool_id'])
|
|
||||||
image_id = 0
|
|
||||||
while image_id == 0:
|
|
||||||
# check if the image already exists and find a free ID
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name } },
|
|
||||||
{ 'request_range': { 'key': 'index/maxid/'+pool_s } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) > 0:
|
|
||||||
# already exists
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' already exists')
|
|
||||||
image_id, id_mod = self._next_id(resp['responses'][1])
|
|
||||||
# try to create the image
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': id_mod, 'key': 'index/maxid/'+pool_s },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+vol_name },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'config/inode/'+pool_s+'/'+str(image_id) },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_put': { 'key': 'index/maxid/'+pool_s, 'value': image_id } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+vol_name, 'value': json.dumps({
|
|
||||||
'id': image_id, 'pool_id': self.cfg['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+pool_s+'/'+str(image_id), 'value': json.dumps({
|
|
||||||
**cfg, 'name': vol_name,
|
|
||||||
}) } },
|
|
||||||
] })
|
|
||||||
if not resp.get('succeeded'):
|
|
||||||
# repeat
|
|
||||||
image_id = 0
|
|
||||||
|
|
||||||
def _create_snapshot(self, vol_name, snap_vol_name, allow_existing = False):
|
|
||||||
while True:
|
|
||||||
# check if the image already exists and snapshot doesn't
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+vol_name } },
|
|
||||||
{ 'request_range': { 'key': 'index/image/'+snap_vol_name } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
if len(resp['responses'][1]['kvs']) > 0:
|
|
||||||
if allow_existing:
|
|
||||||
snap_idx = resp['responses'][1]['kvs'][0]['value']
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'config/inode/'+str(snap_idx['pool_id'])+'/'+str(snap_idx['id']) } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data =
|
|
||||||
'Volume '+snap_vol_name+' is already indexed, but does not exist'
|
|
||||||
)
|
|
||||||
return resp['responses'][0]['kvs'][0]['value']
|
|
||||||
raise exception.VolumeBackendAPIException(
|
|
||||||
data = 'Volume '+snap_vol_name+' already exists'
|
|
||||||
)
|
|
||||||
vol_idx = resp['responses'][0]['kvs'][0]['value']
|
|
||||||
vol_idx_mod = resp['responses'][0]['kvs'][0]['mod_revision']
|
|
||||||
# get image inode config and find a new ID
|
|
||||||
resp = self._etcd_txn({ 'success': [
|
|
||||||
{ 'request_range': { 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']) } },
|
|
||||||
{ 'request_range': { 'key': 'index/maxid/'+str(self.cfg['pool_id']) } },
|
|
||||||
] })
|
|
||||||
if len(resp['responses'][0]['kvs']) == 0:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
vol_cfg = resp['responses'][0]['kvs'][0]['value']
|
|
||||||
vol_mod = resp['responses'][0]['kvs'][0]['mod_revision']
|
|
||||||
new_id, id_mod = self._next_id(resp['responses'][1])
|
|
||||||
# try to redirect image to the new inode
|
|
||||||
new_cfg = {
|
|
||||||
**vol_cfg, 'name': vol_name, 'parent_id': vol_idx['id'], 'parent_pool_id': vol_idx['pool_id']
|
|
||||||
}
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol_idx_mod, 'key': 'index/image/'+vol_name },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol_mod, 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']) },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': id_mod, 'key': 'index/maxid/'+str(self.cfg['pool_id']) },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+snap_vol_name },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'config/inode/'+str(self.cfg['pool_id'])+'/'+str(new_id) },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_put': { 'key': 'index/maxid/'+str(self.cfg['pool_id']), 'value': new_id } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+vol_name, 'value': json.dumps({
|
|
||||||
'id': new_id, 'pool_id': self.cfg['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(self.cfg['pool_id'])+'/'+str(new_id), 'value': json.dumps(new_cfg) } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+snap_vol_name, 'value': json.dumps({
|
|
||||||
'id': vol_idx['id'], 'pool_id': vol_idx['pool_id']
|
|
||||||
}) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(vol_idx['pool_id'])+'/'+str(vol_idx['id']), 'value': json.dumps({
|
|
||||||
**vol_cfg, 'name': snap_vol_name, 'readonly': True
|
|
||||||
}) } }
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
return new_cfg
|
|
||||||
|
|
||||||
def initialize_connection(self, volume, connector):
|
def initialize_connection(self, volume, connector):
|
||||||
data = {
|
data = {
|
||||||
'driver_volume_type': 'vitastor',
|
'driver_volume_type': 'vitastor',
|
||||||
@@ -697,13 +538,9 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
size = int(volume.size) * units.Gi
|
size = int(volume.size) * units.Gi
|
||||||
dest_name = utils.convert_str(volume.name)
|
dest_name = utils.convert_str(volume.name)
|
||||||
# Find or create the base snapshot
|
# Find or create the base snapshot
|
||||||
snap_cfg = self._create_snapshot(base_vol.name, base_vol.name+'@.clone_snap', True)
|
self._cli('create base snapshot', 'create', '--allow-existing', '1', base_vol.name+'@.clone_snap')
|
||||||
# Then create a clone from it
|
# Then create a clone from it
|
||||||
new_cfg = self._create_image(dest_name, {
|
self._cli('create clone', 'create', dest_name, '--size', size, '--parent', base_vol.name+'@.clone_snap')
|
||||||
'size': size,
|
|
||||||
'parent_id': snap_cfg['parent_id'],
|
|
||||||
'parent_pool_id': snap_cfg['parent_pool_id'],
|
|
||||||
})
|
|
||||||
return ({}, True)
|
return ({}, True)
|
||||||
return ({}, False)
|
return ({}, False)
|
||||||
|
|
||||||
@@ -770,26 +607,8 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
def extend_volume(self, volume, new_size):
|
def extend_volume(self, volume, new_size):
|
||||||
"""Extend an existing volume."""
|
"""Extend an existing volume."""
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
while True:
|
size = int(new_size) * units.Gi
|
||||||
vol = self._get_image(vol_name)
|
self._cli('extend volume', 'modify', vol_name, '--resize', new_size)
|
||||||
if not vol:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+vol_name+' does not exist')
|
|
||||||
# change size
|
|
||||||
size = int(new_size) * units.Gi
|
|
||||||
if size == vol['cfg']['size']:
|
|
||||||
break
|
|
||||||
resp = self._etcd_txn({ 'compare': [ {
|
|
||||||
'target': 'MOD',
|
|
||||||
'mod_revision': vol['cfg_mod'],
|
|
||||||
'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
} ], 'success': [
|
|
||||||
{ 'request_put': {
|
|
||||||
'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
'value': json.dumps({ **vol['cfg'], 'size': size }),
|
|
||||||
} },
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
break
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Extend volume from %(old_size)s GB to %(new_size)s GB.",
|
"Extend volume from %(old_size)s GB to %(new_size)s GB.",
|
||||||
{'old_size': volume.size, 'new_size': new_size}
|
{'old_size': volume.size, 'new_size': new_size}
|
||||||
@@ -862,28 +681,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
"""
|
"""
|
||||||
from_name = self._get_existing_name(existing_ref)
|
from_name = self._get_existing_name(existing_ref)
|
||||||
to_name = utils.convert_str(volume.name)
|
to_name = utils.convert_str(volume.name)
|
||||||
self._rename(from_name, to_name)
|
self._cli('rename', 'modify', from_name, '--rename', to_name)
|
||||||
|
|
||||||
def _rename(self, from_name, to_name):
|
|
||||||
while True:
|
|
||||||
vol = self._get_image(from_name)
|
|
||||||
if not vol:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+from_name+' does not exist')
|
|
||||||
to = self._get_image(to_name)
|
|
||||||
if to:
|
|
||||||
raise exception.VolumeBackendAPIException(data = 'Volume '+to_name+' already exists')
|
|
||||||
resp = self._etcd_txn({ 'compare': [
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol['idx_mod'], 'key': 'index/image/'+vol['cfg']['name'] },
|
|
||||||
{ 'target': 'MOD', 'mod_revision': vol['cfg_mod'], 'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']) },
|
|
||||||
{ 'target': 'VERSION', 'version': 0, 'key': 'index/image/'+to_name },
|
|
||||||
], 'success': [
|
|
||||||
{ 'request_delete_range': { 'key': 'index/image/'+vol['cfg']['name'] } },
|
|
||||||
{ 'request_put': { 'key': 'index/image/'+to_name, 'value': json.dumps(vol['idx']) } },
|
|
||||||
{ 'request_put': { 'key': 'config/inode/'+str(vol['idx']['pool_id'])+'/'+str(vol['idx']['id']),
|
|
||||||
'value': json.dumps({ **vol['cfg'], 'name': to_name }) } },
|
|
||||||
] })
|
|
||||||
if resp.get('succeeded'):
|
|
||||||
break
|
|
||||||
|
|
||||||
def unmanage(self, volume):
|
def unmanage(self, volume):
|
||||||
pass
|
pass
|
||||||
@@ -956,7 +754,7 @@ class VitastorDriver(driver.CloneableImageVD,
|
|||||||
snap_name = self._get_existing_name(existing_ref)
|
snap_name = self._get_existing_name(existing_ref)
|
||||||
from_name = vol_name+'@'+snap_name
|
from_name = vol_name+'@'+snap_name
|
||||||
to_name = vol_name+'@'+utils.convert_str(snapshot.name)
|
to_name = vol_name+'@'+utils.convert_str(snapshot.name)
|
||||||
self._rename(from_name, to_name)
|
self._cli('rename', 'modify', from_name, '--rename', to_name)
|
||||||
|
|
||||||
def unmanage_snapshot(self, snapshot):
|
def unmanage_snapshot(self, snapshot):
|
||||||
"""Removes the specified snapshot from Cinder management."""
|
"""Removes the specified snapshot from Cinder management."""
|
||||||
|
|||||||
Reference in New Issue
Block a user