Support revert to snapshot in client
This patch added revert to snapshot support in cinder client, also fix two pylint errors. Change-Id: I20d8df8d7bcf763f6651f44901a98f6d853b27ce Partial-Implements: blueprint revert-volume-to-snapshot Depends-On: cca9e1ac54d123da8859ff918b2355606bfa474e
This commit is contained in:
parent
b910f5bea3
commit
7dfbb239de
cinderclient
releasenotes/notes
@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
# key is a deprecated version and value is an alternative version.
|
# key is a deprecated version and value is an alternative version.
|
||||||
DEPRECATED_VERSIONS = {"1": "2"}
|
DEPRECATED_VERSIONS = {"1": "2"}
|
||||||
DEPRECATED_VERSION = "2.0"
|
DEPRECATED_VERSION = "2.0"
|
||||||
MAX_VERSION = "3.33"
|
MAX_VERSION = "3.40"
|
||||||
MIN_VERSION = "3.0"
|
MIN_VERSION = "3.0"
|
||||||
|
|
||||||
_SUBSTITUTIONS = {}
|
_SUBSTITUTIONS = {}
|
||||||
|
@ -535,6 +535,8 @@ class FakeHTTPClient(base_client.HTTPClient):
|
|||||||
elif action == 'os-volume_upload_image':
|
elif action == 'os-volume_upload_image':
|
||||||
assert 'image_name' in body[action]
|
assert 'image_name' in body[action]
|
||||||
_body = body
|
_body = body
|
||||||
|
elif action == 'revert':
|
||||||
|
assert 'snapshot_id' in body[action]
|
||||||
else:
|
else:
|
||||||
raise AssertionError("Unexpected action: %s" % action)
|
raise AssertionError("Unexpected action: %s" % action)
|
||||||
return (resp, {}, _body)
|
return (resp, {}, _body)
|
||||||
|
@ -23,6 +23,7 @@ from cinderclient import client
|
|||||||
from cinderclient import exceptions
|
from cinderclient import exceptions
|
||||||
from cinderclient import shell
|
from cinderclient import shell
|
||||||
from cinderclient.v3 import volumes
|
from cinderclient.v3 import volumes
|
||||||
|
from cinderclient.v3 import volume_snapshots
|
||||||
from cinderclient.tests.unit import utils
|
from cinderclient.tests.unit import utils
|
||||||
from cinderclient.tests.unit.v3 import fakes
|
from cinderclient.tests.unit.v3 import fakes
|
||||||
from cinderclient.tests.unit.fixture_data import keystone_client
|
from cinderclient.tests.unit.fixture_data import keystone_client
|
||||||
@ -278,6 +279,18 @@ class ShellTest(utils.TestCase):
|
|||||||
self.run_command(command)
|
self.run_command(command)
|
||||||
self.assert_called('GET', '/attachments%s' % expected)
|
self.assert_called('GET', '/attachments%s' % expected)
|
||||||
|
|
||||||
|
@mock.patch('cinderclient.shell_utils.find_volume_snapshot')
|
||||||
|
def test_revert_to_snapshot(self, mock_snapshot):
|
||||||
|
|
||||||
|
mock_snapshot.return_value = volume_snapshots.Snapshot(
|
||||||
|
self, {'id': '5678', 'volume_id': '1234'})
|
||||||
|
|
||||||
|
self.run_command(
|
||||||
|
'--os-volume-api-version 3.40 revert-to-snapshot 5678')
|
||||||
|
|
||||||
|
self.assert_called('POST', '/volumes/1234/action',
|
||||||
|
body={'revert': {'snapshot_id': '5678'}})
|
||||||
|
|
||||||
def test_attachment_show(self):
|
def test_attachment_show(self):
|
||||||
self.run_command('--os-volume-api-version 3.27 attachment-show 1234')
|
self.run_command('--os-volume-api-version 3.27 attachment-show 1234')
|
||||||
self.assert_called('GET', '/attachments/1234')
|
self.assert_called('GET', '/attachments/1234')
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
import ddt
|
import ddt
|
||||||
|
|
||||||
from cinderclient import api_versions
|
from cinderclient import api_versions
|
||||||
|
from cinderclient import exceptions
|
||||||
from cinderclient.tests.unit import utils
|
from cinderclient.tests.unit import utils
|
||||||
from cinderclient.tests.unit.v3 import fakes
|
from cinderclient.tests.unit.v3 import fakes
|
||||||
from cinderclient.v3 import volumes
|
from cinderclient.v3 import volumes
|
||||||
|
from cinderclient.v3 import volume_snapshots
|
||||||
|
|
||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
@ -48,6 +50,28 @@ class VolumesTest(utils.TestCase):
|
|||||||
visibility='public', protected=True)
|
visibility='public', protected=True)
|
||||||
cs.assert_called_anytime('POST', '/volumes/1234/action', body=expected)
|
cs.assert_called_anytime('POST', '/volumes/1234/action', body=expected)
|
||||||
|
|
||||||
|
@ddt.data('3.39', '3.40')
|
||||||
|
def test_revert_to_snapshot(self, version):
|
||||||
|
|
||||||
|
api_version = api_versions.APIVersion(version)
|
||||||
|
cs = fakes.FakeClient(api_version)
|
||||||
|
manager = volumes.VolumeManager(cs)
|
||||||
|
fake_snapshot = volume_snapshots.Snapshot(
|
||||||
|
manager, {'id': 12345, 'name': 'fake-snapshot'}, loaded=True)
|
||||||
|
fake_volume = volumes.Volume(manager,
|
||||||
|
{'id': 1234, 'name': 'sample-volume'},
|
||||||
|
loaded=True)
|
||||||
|
expected = {'revert': {'snapshot_id': 12345}}
|
||||||
|
|
||||||
|
if version == '3.40':
|
||||||
|
fake_volume.revert_to_snapshot(fake_snapshot)
|
||||||
|
|
||||||
|
cs.assert_called_anytime('POST', '/volumes/1234/action',
|
||||||
|
body=expected)
|
||||||
|
else:
|
||||||
|
self.assertRaises(exceptions.VersionNotFoundForAPIMethod,
|
||||||
|
fake_volume.revert_to_snapshot, fake_snapshot)
|
||||||
|
|
||||||
def test_create_volume(self):
|
def test_create_volume(self):
|
||||||
vol = cs.volumes.create(1, group_id='1234', volume_type='5678')
|
vol = cs.volumes.create(1, group_id='1234', volume_type='5678')
|
||||||
expected = {'volume': {'status': 'creating',
|
expected = {'volume': {'status': 'creating',
|
||||||
|
@ -1371,6 +1371,19 @@ def do_api_version(cs, args):
|
|||||||
utils.print_list(response, columns)
|
utils.print_list(response, columns)
|
||||||
|
|
||||||
|
|
||||||
|
@api_versions.wraps("3.40")
|
||||||
|
@utils.arg(
|
||||||
|
'snapshot',
|
||||||
|
metavar='<snapshot>',
|
||||||
|
help='Name or ID of the snapshot to restore. The snapshot must be the '
|
||||||
|
'most recent one known to cinder.')
|
||||||
|
def do_revert_to_snapshot(cs, args):
|
||||||
|
"""Revert a volume to the specified snapshot."""
|
||||||
|
snapshot = shell_utils.find_volume_snapshot(cs, args.snapshot)
|
||||||
|
volume = utils.find_volume(cs, snapshot.volume_id)
|
||||||
|
volume.revert_to_snapshot(snapshot)
|
||||||
|
|
||||||
|
|
||||||
@api_versions.wraps("3.3")
|
@api_versions.wraps("3.3")
|
||||||
@utils.arg('--marker',
|
@utils.arg('--marker',
|
||||||
metavar='<marker>',
|
metavar='<marker>',
|
||||||
|
@ -45,6 +45,10 @@ class Volume(volumes.Volume):
|
|||||||
return self.manager.upload_to_image(self, force, image_name,
|
return self.manager.upload_to_image(self, force, image_name,
|
||||||
container_format, disk_format)
|
container_format, disk_format)
|
||||||
|
|
||||||
|
def revert_to_snapshot(self, snapshot):
|
||||||
|
"""Revert a volume to a snapshot."""
|
||||||
|
self.manager.revert_to_snapshot(self, snapshot)
|
||||||
|
|
||||||
|
|
||||||
class VolumeManager(volumes.VolumeManager):
|
class VolumeManager(volumes.VolumeManager):
|
||||||
resource_class = Volume
|
resource_class = Volume
|
||||||
@ -109,6 +113,17 @@ class VolumeManager(volumes.VolumeManager):
|
|||||||
|
|
||||||
return self._create('/volumes', body, 'volume')
|
return self._create('/volumes', body, 'volume')
|
||||||
|
|
||||||
|
@api_versions.wraps('3.40')
|
||||||
|
def revert_to_snapshot(self, volume, snapshot):
|
||||||
|
"""Revert a volume to a snapshot.
|
||||||
|
|
||||||
|
The snapshot must be the most recent one known to cinder.
|
||||||
|
:param volume: volume object.
|
||||||
|
:param snapshot: snapshot object.
|
||||||
|
"""
|
||||||
|
return self._action('revert', volume,
|
||||||
|
info={'snapshot_id': base.getid(snapshot.id)})
|
||||||
|
|
||||||
@api_versions.wraps("3.0")
|
@api_versions.wraps("3.0")
|
||||||
def delete_metadata(self, volume, keys):
|
def delete_metadata(self, volume, keys):
|
||||||
"""Delete specified keys from volumes metadata.
|
"""Delete specified keys from volumes metadata.
|
||||||
@ -131,6 +146,7 @@ class VolumeManager(volumes.VolumeManager):
|
|||||||
:param volume: The :class:`Volume`.
|
:param volume: The :class:`Volume`.
|
||||||
:param keys: A list of keys to be removed.
|
:param keys: A list of keys to be removed.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=function-redefined
|
||||||
data = self._get("/volumes/%s/metadata" % base.getid(volume))
|
data = self._get("/volumes/%s/metadata" % base.getid(volume))
|
||||||
metadata = data._info.get("metadata", {})
|
metadata = data._info.get("metadata", {})
|
||||||
if set(keys).issubset(metadata.keys()):
|
if set(keys).issubset(metadata.keys()):
|
||||||
@ -160,6 +176,7 @@ class VolumeManager(volumes.VolumeManager):
|
|||||||
"""Upload volume to image service as image.
|
"""Upload volume to image service as image.
|
||||||
:param volume: The :class:`Volume` to upload.
|
:param volume: The :class:`Volume` to upload.
|
||||||
"""
|
"""
|
||||||
|
# pylint: disable=function-redefined
|
||||||
return self._action('os-volume_upload_image',
|
return self._action('os-volume_upload_image',
|
||||||
volume,
|
volume,
|
||||||
{'force': force,
|
{'force': force,
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added support for the revert-to-snapshot feature.
|
Loading…
x
Reference in New Issue
Block a user