Add volume reimage command
A new reimage API will be introduced on cinder API side with change in depends on. This patch provides the CLI support for the same by adding a reimage command. Implements: blueprint add-volume-re-image-api Change-Id: I37c254d4caf2f416e456ff6a78b5a4df4e08a176
This commit is contained in:
parent
af3bc66a5f
commit
12075cb710
@ -26,7 +26,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# key is unsupported version, value is appropriate supported alternative
|
# key is unsupported version, value is appropriate supported alternative
|
||||||
REPLACEMENT_VERSIONS = {"1": "3", "2": "3"}
|
REPLACEMENT_VERSIONS = {"1": "3", "2": "3"}
|
||||||
MAX_VERSION = "3.66"
|
MAX_VERSION = "3.68"
|
||||||
MIN_VERSION = "3.0"
|
MIN_VERSION = "3.0"
|
||||||
|
|
||||||
_SUBSTITUTIONS = {}
|
_SUBSTITUTIONS = {}
|
||||||
|
@ -453,6 +453,8 @@ class FakeHTTPClient(fakes_base.FakeHTTPClient):
|
|||||||
'failover_replication', 'list_replication_targets',
|
'failover_replication', 'list_replication_targets',
|
||||||
'reset_status'):
|
'reset_status'):
|
||||||
assert action in body
|
assert action in body
|
||||||
|
elif action == 'os-reimage':
|
||||||
|
assert 'image_id' in body[action]
|
||||||
else:
|
else:
|
||||||
raise AssertionError("Unexpected action: %s" % action)
|
raise AssertionError("Unexpected action: %s" % action)
|
||||||
return (resp, {}, {})
|
return (resp, {}, {})
|
||||||
|
@ -550,6 +550,8 @@ class FakeHTTPClient(base_client.HTTPClient):
|
|||||||
_body = body
|
_body = body
|
||||||
elif action == 'revert':
|
elif action == 'revert':
|
||||||
assert 'snapshot_id' in body[action]
|
assert 'snapshot_id' in body[action]
|
||||||
|
elif action == 'os-reimage':
|
||||||
|
assert 'image_id' in body[action]
|
||||||
else:
|
else:
|
||||||
raise AssertionError("Unexpected action: %s" % action)
|
raise AssertionError("Unexpected action: %s" % action)
|
||||||
return (resp, {}, _body)
|
return (resp, {}, _body)
|
||||||
|
@ -1895,3 +1895,18 @@ class ShellTest(utils.TestCase):
|
|||||||
'volume_id': '1234',
|
'volume_id': '1234',
|
||||||
'volume_name': volume_name,
|
'volume_name': volume_name,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_reimage(self):
|
||||||
|
self.run_command('--os-volume-api-version 3.68 reimage 1234 1')
|
||||||
|
expected = {'os-reimage': {'image_id': '1',
|
||||||
|
'reimage_reserved': False}}
|
||||||
|
self.assert_called('POST', '/volumes/1234/action', body=expected)
|
||||||
|
|
||||||
|
@ddt.data('False', 'True')
|
||||||
|
def test_reimage_reserved(self, reimage_reserved):
|
||||||
|
self.run_command(
|
||||||
|
'--os-volume-api-version 3.68 reimage --reimage-reserved %s 1234 1'
|
||||||
|
% reimage_reserved)
|
||||||
|
expected = {'os-reimage': {'image_id': '1',
|
||||||
|
'reimage_reserved': reimage_reserved}}
|
||||||
|
self.assert_called('POST', '/volumes/1234/action', body=expected)
|
||||||
|
@ -201,3 +201,15 @@ class VolumesTest(utils.TestCase):
|
|||||||
'force_host_copy': False,
|
'force_host_copy': False,
|
||||||
'lock_volume': False}})
|
'lock_volume': False}})
|
||||||
self._assert_request_id(vol)
|
self._assert_request_id(vol)
|
||||||
|
|
||||||
|
@ddt.data(False, True)
|
||||||
|
def test_reimage(self, reimage_reserved):
|
||||||
|
cs = fakes.FakeClient(api_versions.APIVersion('3.68'))
|
||||||
|
v = cs.volumes.get('1234')
|
||||||
|
self._assert_request_id(v)
|
||||||
|
vol = cs.volumes.reimage(v, '1', reimage_reserved)
|
||||||
|
cs.assert_called('POST', '/volumes/1234/action',
|
||||||
|
{'os-reimage': {'image_id': '1',
|
||||||
|
'reimage_reserved':
|
||||||
|
reimage_reserved}})
|
||||||
|
self._assert_request_id(vol)
|
||||||
|
@ -2858,3 +2858,23 @@ def do_default_type_unset(cs, args):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Unset for default volume type for project %s failed: %s"
|
print("Unset for default volume type for project %s failed: %s"
|
||||||
% (project_id, e))
|
% (project_id, e))
|
||||||
|
|
||||||
|
|
||||||
|
@api_versions.wraps('3.68')
|
||||||
|
@utils.arg('volume',
|
||||||
|
metavar='<volume>',
|
||||||
|
help='Name or ID of volume to reimage')
|
||||||
|
@utils.arg('image_id',
|
||||||
|
metavar='<image-id>',
|
||||||
|
help='The image id of the image that will be used to reimage '
|
||||||
|
'the volume.')
|
||||||
|
@utils.arg('--reimage-reserved',
|
||||||
|
metavar='<True|False>',
|
||||||
|
default=False,
|
||||||
|
help='Enables or disables reimage for a volume that is in '
|
||||||
|
'reserved state otherwise only volumes in "available" '
|
||||||
|
' or "error" status may be re-imaged. Default=False.')
|
||||||
|
def do_reimage(cs, args):
|
||||||
|
"""Rebuilds a volume, overwriting all content with the specified image"""
|
||||||
|
volume = utils.find_volume(cs, args.volume)
|
||||||
|
volume.reimage(args.image_id, args.reimage_reserved)
|
||||||
|
@ -67,6 +67,10 @@ class Volume(volumes_base.Volume):
|
|||||||
metadata=metadata, bootable=bootable,
|
metadata=metadata, bootable=bootable,
|
||||||
cluster=cluster)
|
cluster=cluster)
|
||||||
|
|
||||||
|
def reimage(self, image_id, reimage_reserved=False):
|
||||||
|
"""Rebuilds the volume with the new specified image"""
|
||||||
|
self.manager.reimage(self, image_id, reimage_reserved)
|
||||||
|
|
||||||
|
|
||||||
class VolumeManager(volumes_base.VolumeManager):
|
class VolumeManager(volumes_base.VolumeManager):
|
||||||
resource_class = Volume
|
resource_class = Volume
|
||||||
@ -282,3 +286,21 @@ class VolumeManager(volumes_base.VolumeManager):
|
|||||||
search_opts=options)
|
search_opts=options)
|
||||||
|
|
||||||
return self._get(url, None)
|
return self._get(url, None)
|
||||||
|
|
||||||
|
@api_versions.wraps('3.68')
|
||||||
|
def reimage(self, volume, image_id, reimage_reserved=False):
|
||||||
|
"""Reimage a volume
|
||||||
|
|
||||||
|
.. warning:: This is a destructive action and the contents of the
|
||||||
|
volume will be lost.
|
||||||
|
|
||||||
|
:param volume: Volume to reimage.
|
||||||
|
:param reimage_reserved: Boolean to enable or disable reimage
|
||||||
|
of a volume that is in 'reserved' state otherwise only
|
||||||
|
volumes in 'available' status may be re-imaged.
|
||||||
|
:param image_id: The image id.
|
||||||
|
"""
|
||||||
|
return self._action('os-reimage',
|
||||||
|
volume,
|
||||||
|
{'image_id': image_id,
|
||||||
|
'reimage_reserved': reimage_reserved})
|
||||||
|
10
releasenotes/notes/reimage-volume-fea3a1178662e65a.yaml
Normal file
10
releasenotes/notes/reimage-volume-fea3a1178662e65a.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
A new ``cinder reimage`` command and related python API binding has been
|
||||||
|
added which allows a user to replace the current content of a specified
|
||||||
|
volume with the data of a specified image supplied by the Image service
|
||||||
|
(Glance). (Note that this is a destructive action, that is, all data
|
||||||
|
currently contained in the volume is destroyed when the volume is
|
||||||
|
re-imaged.) This feature requires Block Storage API microversion 3.68
|
||||||
|
or greater.
|
Loading…
Reference in New Issue
Block a user