Add snapshot instances admin CLIs
Support new API entry points for share snapshot instances: - share-snapshot-instance-list - share-snapshot-instance-show - share-snapshot-instance-reset-status Implements: blueprint snapshot-instances Change-Id: Ica1e81012f19926e0f1ba9cd6d8eecc5fbbf40b5
This commit is contained in:
parent
947989952a
commit
5de1ef3844
@ -27,7 +27,7 @@ from manilaclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MAX_VERSION = '2.17'
|
||||
MAX_VERSION = '2.19'
|
||||
MIN_VERSION = '2.0'
|
||||
DEPRECATED_VERSION = '1.0'
|
||||
_VERSIONED_METHOD_MAP = {}
|
||||
|
@ -125,6 +125,11 @@ share_opts = [
|
||||
default="TESTDOMAIN\\Administrator",
|
||||
help="Username, that will be used in share access tests for "
|
||||
"user type of access."),
|
||||
cfg.BoolOpt("run_snapshot_tests",
|
||||
default=True,
|
||||
help="Defines whether to run tests that use share snapshots "
|
||||
"or not. Disable this feature if used driver doesn't "
|
||||
"support it."),
|
||||
]
|
||||
|
||||
# 2. Generate config
|
||||
|
@ -105,6 +105,11 @@ class BaseTestCase(base.ClientTestBase):
|
||||
res_id, microversion=res["microversion"])
|
||||
client.wait_for_share_deletion(
|
||||
res_id, microversion=res["microversion"])
|
||||
elif res["type"] is "snapshot":
|
||||
client.delete_snapshot(
|
||||
res_id, microversion=res["microversion"])
|
||||
client.wait_for_snapshot_deletion(
|
||||
res_id, microversion=res["microversion"])
|
||||
else:
|
||||
LOG.warning("Provided unsupported resource type for "
|
||||
"cleanup '%s'. Skipping." % res["type"])
|
||||
@ -277,3 +282,31 @@ class BaseTestCase(base.ClientTestBase):
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
return ss
|
||||
|
||||
@classmethod
|
||||
def create_snapshot(cls, share, name=None, description=None,
|
||||
force=False, client=None, wait_for_creation=True,
|
||||
cleanup_in_class=False, microversion=None):
|
||||
if client is None:
|
||||
client = cls.get_admin_client()
|
||||
data = {
|
||||
'share': share,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'force': force,
|
||||
'microversion': microversion,
|
||||
}
|
||||
snapshot = client.create_snapshot(**data)
|
||||
resource = {
|
||||
"type": "snapshot",
|
||||
"id": snapshot["id"],
|
||||
"client": client,
|
||||
"microversion": microversion,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
if wait_for_creation:
|
||||
client.wait_for_snapshot_status(snapshot['id'], 'available')
|
||||
return snapshot
|
||||
|
@ -125,6 +125,8 @@ class ManilaCLIClient(base.CLIClient):
|
||||
func = self.is_share_network_deleted
|
||||
elif res_type == SHARE:
|
||||
func = self.is_share_deleted
|
||||
elif res_type == SNAPSHOT:
|
||||
func = self.is_snapshot_deleted
|
||||
else:
|
||||
raise exceptions.InvalidResource(message=res_type)
|
||||
|
||||
@ -692,6 +694,112 @@ class ManilaCLIClient(base.CLIClient):
|
||||
metadata = output_parser.details(metadata_raw)
|
||||
return metadata
|
||||
|
||||
def create_snapshot(self, share, name=None, description=None,
|
||||
force=False, microversion=None):
|
||||
"""Creates a snapshot."""
|
||||
cmd = 'snapshot-create %(share)s ' % {'share': share}
|
||||
if name is None:
|
||||
name = data_utils.rand_name('autotest_snapshot_name')
|
||||
cmd += '--name %s ' % name
|
||||
if description is None:
|
||||
description = data_utils.rand_name('autotest_snapshot_description')
|
||||
cmd += '--description %s ' % description
|
||||
if force:
|
||||
cmd += '--force %s' % force
|
||||
snapshot_raw = self.manila(cmd, microversion=microversion)
|
||||
snapshot = output_parser.details(snapshot_raw)
|
||||
return snapshot
|
||||
|
||||
@not_found_wrapper
|
||||
def get_snapshot(self, snapshot, microversion=None):
|
||||
"""Retrieves a snapshot by its Name or ID."""
|
||||
snapshot_raw = self.manila('snapshot-show %s' % snapshot,
|
||||
microversion=microversion)
|
||||
snapshot = output_parser.details(snapshot_raw)
|
||||
return snapshot
|
||||
|
||||
@not_found_wrapper
|
||||
@forbidden_wrapper
|
||||
def delete_snapshot(self, snapshot, microversion=None):
|
||||
"""Deletes snapshot by Names or IDs."""
|
||||
return self.manila(
|
||||
"snapshot-delete %s" % snapshot, microversion=microversion)
|
||||
|
||||
def list_snapshot_instances(self, snapshot_id=None, columns=None,
|
||||
detailed=None, microversion=None):
|
||||
"""List snapshot instances."""
|
||||
cmd = 'snapshot-instance-list '
|
||||
if snapshot_id:
|
||||
cmd += '--snapshot %s' % snapshot_id
|
||||
if columns is not None:
|
||||
cmd += ' --columns ' + columns
|
||||
if detailed:
|
||||
cmd += ' --detailed True '
|
||||
snapshot_instances_raw = self.manila(cmd, microversion=microversion)
|
||||
snapshot_instances = utils.listing(snapshot_instances_raw)
|
||||
return snapshot_instances
|
||||
|
||||
def get_snapshot_instance(self, id=None, microversion=None):
|
||||
"""Get snapshot instance."""
|
||||
cmd = 'snapshot-instance-show %s ' % id
|
||||
snapshot_instance_raw = self.manila(cmd, microversion=microversion)
|
||||
snapshot_instance = output_parser.details(snapshot_instance_raw)
|
||||
return snapshot_instance
|
||||
|
||||
def reset_snapshot_instance(self, id=None, state=None, microversion=None):
|
||||
"""Reset snapshot instance status."""
|
||||
cmd = 'snapshot-instance-reset-state %s ' % id
|
||||
if state:
|
||||
cmd += '--state %s' % state
|
||||
snapshot_instance_raw = self.manila(cmd, microversion=microversion)
|
||||
snapshot_instance = utils.listing(snapshot_instance_raw)
|
||||
return snapshot_instance
|
||||
|
||||
def is_snapshot_deleted(self, snapshot, microversion=None):
|
||||
"""Indicates whether snapshot is deleted or not.
|
||||
|
||||
:param snapshot: str -- Name or ID of snapshot
|
||||
"""
|
||||
try:
|
||||
self.get_snapshot(snapshot, microversion=microversion)
|
||||
return False
|
||||
except tempest_lib_exc.NotFound:
|
||||
return True
|
||||
|
||||
def wait_for_snapshot_deletion(self, snapshot, microversion=None):
|
||||
"""Wait for snapshot deletion by its Name or ID.
|
||||
|
||||
:param snapshot: str -- Name or ID of snapshot
|
||||
"""
|
||||
self.wait_for_resource_deletion(
|
||||
SNAPSHOT, res_id=snapshot, interval=5, timeout=300,
|
||||
microversion=microversion)
|
||||
|
||||
def wait_for_snapshot_status(self, snapshot, status, microversion=None):
|
||||
"""Waits for a snapshot to reach a given status."""
|
||||
body = self.get_snapshot(snapshot, microversion=microversion)
|
||||
snapshot_name = body['name']
|
||||
snapshot_status = body['status']
|
||||
start = int(time.time())
|
||||
|
||||
while snapshot_status != status:
|
||||
time.sleep(self.build_interval)
|
||||
body = self.get_snapshot(snapshot, microversion=microversion)
|
||||
snapshot_status = body['status']
|
||||
|
||||
if snapshot_status == status:
|
||||
return
|
||||
elif 'error' in snapshot_status.lower():
|
||||
raise exceptions.SnapshotBuildErrorException(snapshot=snapshot)
|
||||
|
||||
if int(time.time()) - start >= self.build_timeout:
|
||||
message = (
|
||||
"Snapshot %(snapshot_name)s failed to reach %(status)s "
|
||||
"status within the required time (%(timeout)s s)." % {
|
||||
"snapshot_name": snapshot_name, "status": status,
|
||||
"timeout": self.build_timeout})
|
||||
raise tempest_lib_exc.TimeoutException(message)
|
||||
|
||||
@not_found_wrapper
|
||||
def list_access(self, share_id, columns=None, microversion=None):
|
||||
"""Returns list of access rules for a share.
|
||||
|
@ -33,7 +33,7 @@ class InvalidData(exceptions.TempestException):
|
||||
|
||||
|
||||
class ShareTypeNotFound(exceptions.NotFound):
|
||||
message = "Share type '%(share_type)s' was not found"
|
||||
message = "Share type '%(share_type)s' was not found."
|
||||
|
||||
|
||||
class InvalidConfiguration(exceptions.TempestException):
|
||||
@ -41,7 +41,11 @@ class InvalidConfiguration(exceptions.TempestException):
|
||||
|
||||
|
||||
class ShareBuildErrorException(exceptions.TempestException):
|
||||
message = "Share %(share)s failed to build and is in ERROR status"
|
||||
message = "Share %(share)s failed to build and is in ERROR status."
|
||||
|
||||
|
||||
class SnapshotBuildErrorException(exceptions.TempestException):
|
||||
message = "Snapshot %(snapshot)s failed to build and is in ERROR status."
|
||||
|
||||
|
||||
class AccessRuleCreateErrorException(exceptions.TempestException):
|
||||
|
122
manilaclient/tests/functional/test_snapshot_instances.py
Normal file
122
manilaclient/tests/functional/test_snapshot_instances.py
Normal file
@ -0,0 +1,122 @@
|
||||
# Copyright 2016 Huawei inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
from oslo_utils import uuidutils
|
||||
import testtools
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional import base
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@testtools.skipUnless(CONF.run_snapshot_tests,
|
||||
'Snapshot tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported('2.19')
|
||||
class SnapshotInstancesTest(base.BaseTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(SnapshotInstancesTest, cls).setUpClass()
|
||||
cls.share = cls.create_share(
|
||||
client=cls.get_user_client(),
|
||||
cleanup_in_class=True)
|
||||
cls.snapshot = cls.create_snapshot(share=cls.share['id'],
|
||||
client=cls.get_user_client(),
|
||||
cleanup_in_class=True)
|
||||
|
||||
def test_list_all_snapshot_instances(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances()
|
||||
|
||||
self.assertTrue(len(snapshot_instances) > 0)
|
||||
expected_keys = ('ID', 'Snapshot ID', 'Status')
|
||||
for si in snapshot_instances:
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, si)
|
||||
self.assertTrue(uuidutils.is_uuid_like(si['ID']))
|
||||
self.assertTrue(uuidutils.is_uuid_like(si['Snapshot ID']))
|
||||
|
||||
def test_list_all_snapshot_instances_details(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances(
|
||||
detailed=True)
|
||||
|
||||
self.assertTrue(len(snapshot_instances) > 0)
|
||||
expected_keys = ('ID', 'Snapshot ID', 'Status', 'Created_at',
|
||||
'Updated_at', 'Share_id', 'Share_instance_id',
|
||||
'Progress', 'Provider_location')
|
||||
for si in snapshot_instances:
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, si)
|
||||
for key in ('ID', 'Snapshot ID', 'Share_id', 'Share_instance_id'):
|
||||
self.assertTrue(
|
||||
uuidutils.is_uuid_like(si[key]))
|
||||
|
||||
def test_list_snapshot_instance_with_snapshot(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances(
|
||||
snapshot_id=self.snapshot['id'])
|
||||
|
||||
self.assertEqual(1, len(snapshot_instances))
|
||||
expected_keys = ('ID', 'Snapshot ID', 'Status')
|
||||
for si in snapshot_instances:
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, si)
|
||||
self.assertTrue(uuidutils.is_uuid_like(si['ID']))
|
||||
self.assertTrue(uuidutils.is_uuid_like(si['Snapshot ID']))
|
||||
|
||||
def test_list_snapshot_instance_with_columns(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances(
|
||||
self.snapshot['id'], columns='id,status')
|
||||
|
||||
self.assertTrue(len(snapshot_instances) > 0)
|
||||
expected_keys = ('Id', 'Status')
|
||||
unexpected_keys = ('Snapshot ID', )
|
||||
for si in snapshot_instances:
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, si)
|
||||
for key in unexpected_keys:
|
||||
self.assertNotIn(key, si)
|
||||
self.assertTrue(uuidutils.is_uuid_like(si['Id']))
|
||||
|
||||
def test_get_snapshot_instance(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances(
|
||||
self.snapshot['id'])
|
||||
|
||||
snapshot_instance = self.admin_client.get_snapshot_instance(
|
||||
snapshot_instances[0]['ID'])
|
||||
self.assertTrue(len(snapshot_instance) > 0)
|
||||
expected_keys = ('id', 'snapshot_id', 'status', 'created_at',
|
||||
'updated_at', 'share_id', 'share_instance_id',
|
||||
'progress', 'provider_location')
|
||||
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, snapshot_instance)
|
||||
for key in ('id', 'snapshot_id', 'share_id', 'share_instance_id'):
|
||||
self.assertTrue(
|
||||
uuidutils.is_uuid_like(snapshot_instance[key]))
|
||||
|
||||
def test_snapshot_instance_reset_state(self):
|
||||
snapshot_instances = self.admin_client.list_snapshot_instances(
|
||||
self.snapshot['id'])
|
||||
self.admin_client.reset_snapshot_instance(
|
||||
snapshot_instances[0]['ID'], 'error')
|
||||
snapshot_instance = self.admin_client.get_snapshot_instance(
|
||||
snapshot_instances[0]['ID'])
|
||||
|
||||
self.assertEqual('error', snapshot_instance['status'])
|
||||
self.admin_client.reset_snapshot_instance(snapshot_instance['id'],
|
||||
'available')
|
@ -749,6 +749,53 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
||||
|
||||
get_types_3_share_type_access = get_types_3_os_share_type_access
|
||||
|
||||
fake_snapshot_instance = {
|
||||
"id": "1234",
|
||||
"snapshot_id": "5678",
|
||||
"status": "error",
|
||||
}
|
||||
|
||||
def get_snapshot_instances(self, **kw):
|
||||
instances = {
|
||||
'snapshot_instances': [
|
||||
self.fake_snapshot_instance,
|
||||
]
|
||||
}
|
||||
return (200, {}, instances)
|
||||
|
||||
def get_snapshot_instances_detail(self, **kw):
|
||||
instances = {
|
||||
'snapshot_instances': [
|
||||
{
|
||||
'id': '1234',
|
||||
'snapshot_id': '5679',
|
||||
'created_at': 'fake',
|
||||
'updated_at': 'fake',
|
||||
'status': 'fake',
|
||||
'share_id': 'fake',
|
||||
'share_instance_id': 'fake',
|
||||
'progress': 'fake',
|
||||
'provider_location': 'fake',
|
||||
}
|
||||
]
|
||||
}
|
||||
return (200, {}, instances)
|
||||
|
||||
def get_snapshot_instances_1234(self, **kw):
|
||||
instances = {'snapshot_instance': self.fake_snapshot_instance}
|
||||
return (200, {}, instances)
|
||||
|
||||
def post_snapshot_instances_1234_action(self, body, **kw):
|
||||
_body = None
|
||||
resp = 202
|
||||
assert len(list(body)) == 1
|
||||
action = list(body)[0]
|
||||
if action == 'reset_status':
|
||||
assert 'status' in body.get(action)
|
||||
else:
|
||||
raise AssertionError("Unexpected share action: %s" % action)
|
||||
return (resp, {}, _body)
|
||||
|
||||
|
||||
def fake_create(url, body, response_key):
|
||||
return {'url': url, 'body': body, 'resp_key': response_key}
|
||||
|
95
manilaclient/tests/unit/v2/test_share_snapshot_instances.py
Normal file
95
manilaclient/tests/unit/v2/test_share_snapshot_instances.py
Normal file
@ -0,0 +1,95 @@
|
||||
# Copyright 2016 Huawei inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient import exceptions
|
||||
from manilaclient import extension
|
||||
from manilaclient.tests.unit import utils
|
||||
from manilaclient.tests.unit.v2 import fakes
|
||||
from manilaclient.v2 import share_snapshot_instances
|
||||
|
||||
|
||||
extensions = [
|
||||
extension.Extension('share_snapshot_instances', share_snapshot_instances),
|
||||
]
|
||||
cs = fakes.FakeClient(extensions=extensions)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SnapshotInstancesTest(utils.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SnapshotInstancesTest, self).setUp()
|
||||
microversion = api_versions.APIVersion("2.19")
|
||||
mock_microversion = mock.Mock(api_version=microversion)
|
||||
self.manager = share_snapshot_instances.ShareSnapshotInstanceManager(
|
||||
api=mock_microversion)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_list(self, detailed):
|
||||
if detailed:
|
||||
url = '/snapshot-instances/detail'
|
||||
else:
|
||||
url = '/snapshot-instances'
|
||||
self.mock_object(self.manager, '_list', mock.Mock())
|
||||
self.manager.list(detailed=detailed)
|
||||
self.manager._list.assert_called_once_with(url, 'snapshot_instances')
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_list_with_snapshot(self, detailed):
|
||||
if detailed:
|
||||
url = '/snapshot-instances/detail'
|
||||
else:
|
||||
url = '/snapshot-instances'
|
||||
self.mock_object(self.manager, '_list', mock.Mock())
|
||||
self.manager.list(detailed=detailed, snapshot='snapshot_id')
|
||||
self.manager._list.assert_called_once_with(
|
||||
(url + '?snapshot_id=snapshot_id'), 'snapshot_instances',)
|
||||
|
||||
def test_get(self):
|
||||
self.mock_object(self.manager, '_get', mock.Mock())
|
||||
self.manager.get('fake_snapshot_instance')
|
||||
self.manager._get.assert_called_once_with(
|
||||
'/snapshot-instances/' + 'fake_snapshot_instance',
|
||||
'snapshot_instance')
|
||||
|
||||
def test_reset_instance_state(self):
|
||||
state = 'available'
|
||||
|
||||
self.mock_object(self.manager, '_action', mock.Mock())
|
||||
self.manager.reset_state('fake_instance', state)
|
||||
self.manager._action.assert_called_once_with(
|
||||
"reset_status", 'fake_instance', {"status": state})
|
||||
|
||||
@ddt.data('get', 'list', 'reset_state')
|
||||
def test_upsupported_microversion(self, method_name):
|
||||
unsupported_microversions = ('1.0', '2.18')
|
||||
arguments = {
|
||||
'instance': 'FAKE_INSTANCE',
|
||||
}
|
||||
if method_name in ('list'):
|
||||
arguments.clear()
|
||||
|
||||
for microversion in unsupported_microversions:
|
||||
microversion = api_versions.APIVersion(microversion)
|
||||
mock_microversion = mock.Mock(api_version=microversion)
|
||||
manager = share_snapshot_instances.ShareSnapshotInstanceManager(
|
||||
api=mock_microversion)
|
||||
method = getattr(manager, method_name)
|
||||
self.assertRaises(exceptions.UnsupportedVersion,
|
||||
method, **arguments)
|
@ -1826,3 +1826,39 @@ class ShellTest(test_utils.TestCase):
|
||||
self.assert_called(
|
||||
'POST', '/share-replicas/1234/action',
|
||||
body={action_name: {attr: 'xyzzyspoon!'}})
|
||||
|
||||
def test_snapshot_instance_list_all(self):
|
||||
self.run_command('snapshot-instance-list')
|
||||
self.assert_called('GET', '/snapshot-instances')
|
||||
|
||||
def test_snapshot_instance_list_all_detail(self):
|
||||
self.run_command('snapshot-instance-list --detail True')
|
||||
self.assert_called('GET', '/snapshot-instances/detail')
|
||||
|
||||
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
||||
def test_snapshot_instance_list_select_column(self):
|
||||
self.run_command('snapshot-instance-list --columns id,status')
|
||||
self.assert_called('GET', '/snapshot-instances')
|
||||
cliutils.print_list.assert_called_once_with(
|
||||
mock.ANY, ['Id', 'Status'])
|
||||
|
||||
@mock.patch.object(shell_v2, '_find_share_snapshot', mock.Mock())
|
||||
def test_snapshot_instance_list_for_snapshot(self):
|
||||
fsnapshot = type('FakeSansphot', (object,),
|
||||
{'id': 'fake-snapshot-id'})
|
||||
shell_v2._find_share_snapshot.return_value = fsnapshot
|
||||
cmd = 'snapshot-instance-list --snapshot %s'
|
||||
self.run_command(cmd % fsnapshot.id)
|
||||
|
||||
self.assert_called(
|
||||
'GET', '/snapshot-instances?snapshot_id=fake-snapshot-id')
|
||||
|
||||
def test_snapshot_instance_show(self):
|
||||
self.run_command('snapshot-instance-show 1234')
|
||||
self.assert_called('GET', '/snapshot-instances/1234')
|
||||
|
||||
def test_snapshot_instance_reset_state(self):
|
||||
self.run_command('snapshot-instance-reset-state 1234')
|
||||
expected = {'reset_status': {'status': 'available'}}
|
||||
self.assert_called('POST', '/snapshot-instances/1234/action',
|
||||
body=expected)
|
||||
|
@ -36,6 +36,7 @@ from manilaclient.v2 import share_instances
|
||||
from manilaclient.v2 import share_networks
|
||||
from manilaclient.v2 import share_replicas
|
||||
from manilaclient.v2 import share_servers
|
||||
from manilaclient.v2 import share_snapshot_instances
|
||||
from manilaclient.v2 import share_snapshots
|
||||
from manilaclient.v2 import share_type_access
|
||||
from manilaclient.v2 import share_types
|
||||
@ -220,6 +221,8 @@ class Client(object):
|
||||
share_instance_export_locations.ShareInstanceExportLocationManager(
|
||||
self))
|
||||
self.share_snapshots = share_snapshots.ShareSnapshotManager(self)
|
||||
self.share_snapshot_instances = (
|
||||
share_snapshot_instances.ShareSnapshotInstanceManager(self))
|
||||
|
||||
self.share_types = share_types.ShareTypeManager(self)
|
||||
self.share_type_access = share_type_access.ShareTypeAccessManager(self)
|
||||
|
74
manilaclient/v2/share_snapshot_instances.py
Normal file
74
manilaclient/v2/share_snapshot_instances.py
Normal file
@ -0,0 +1,74 @@
|
||||
# Copyright 2016 Huawei inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient import base
|
||||
from manilaclient.openstack.common.apiclient import base as common_base
|
||||
|
||||
|
||||
class ShareSnapshotInstance(common_base.Resource):
|
||||
"""A snapshot instance is an instance of a snapshot."""
|
||||
|
||||
def __repr__(self):
|
||||
return "<SnapshotInstance: %s>" % self.id
|
||||
|
||||
def reset_state(self, state):
|
||||
"""Update snapshot instance's 'status' attr."""
|
||||
self.manager.reset_state(self, state)
|
||||
|
||||
|
||||
class ShareSnapshotInstanceManager(base.ManagerWithFind):
|
||||
"""Manage :class:`SnapshotInstances` resources."""
|
||||
resource_class = ShareSnapshotInstance
|
||||
|
||||
@api_versions.wraps("2.19")
|
||||
def get(self, instance):
|
||||
"""Get a snapshot instance.
|
||||
|
||||
:param instance: either snapshot instance object or text with its ID.
|
||||
:rtype: :class:`ShareSnapshotInstance`
|
||||
"""
|
||||
snapshot_instance_id = common_base.getid(instance)
|
||||
return self._get("/snapshot-instances/%s" % snapshot_instance_id,
|
||||
"snapshot_instance")
|
||||
|
||||
@api_versions.wraps("2.19")
|
||||
def list(self, detailed=False, snapshot=None):
|
||||
"""List all snapshot instances."""
|
||||
if detailed:
|
||||
url = '/snapshot-instances/detail'
|
||||
else:
|
||||
url = '/snapshot-instances'
|
||||
|
||||
if snapshot:
|
||||
url += '?snapshot_id=%s' % common_base.getid(snapshot)
|
||||
return self._list(url, 'snapshot_instances')
|
||||
|
||||
@api_versions.wraps("2.19")
|
||||
def reset_state(self, instance, state):
|
||||
"""Reset the 'status' attr of the snapshot instance.
|
||||
|
||||
:param instance: either snapshot instance object or its UUID.
|
||||
:param state: state to set the snapshot instance's 'status' attr to.
|
||||
"""
|
||||
return self._action("reset_status", instance, {"status": state})
|
||||
|
||||
def _action(self, action, instance, info=None, **kwargs):
|
||||
"""Perform a snapshot instance 'action'."""
|
||||
body = {action: info}
|
||||
self.run_hooks('modify_body_for_action', body, **kwargs)
|
||||
url = ('/snapshot-instances/%s/action' %
|
||||
common_base.getid(instance))
|
||||
return self.api.client.post(url, body=body)
|
@ -220,6 +220,12 @@ def _print_share_snapshot(cs, snapshot):
|
||||
cliutils.print_dict(info)
|
||||
|
||||
|
||||
def _find_share_snapshot_instance(cs, snapshot_instance):
|
||||
"""Get a share snapshot instance by ID."""
|
||||
return apiclient_utils.find_resource(
|
||||
cs.share_snapshot_instances, snapshot_instance)
|
||||
|
||||
|
||||
def _find_share_network(cs, share_network):
|
||||
"""Get a share network by ID or name."""
|
||||
return apiclient_utils.find_resource(cs.share_networks, share_network)
|
||||
@ -1742,6 +1748,76 @@ def do_snapshot_reset_state(cs, args):
|
||||
snapshot.reset_state(args.state)
|
||||
|
||||
|
||||
@api_versions.wraps("2.19")
|
||||
@cliutils.arg(
|
||||
'--snapshot',
|
||||
metavar='<snapshot>',
|
||||
default=None,
|
||||
help='Filter results by share snapshot ID.')
|
||||
@cliutils.arg(
|
||||
'--columns',
|
||||
metavar='<columns>',
|
||||
type=str,
|
||||
default=None,
|
||||
help='Comma separated list of columns to be displayed '
|
||||
'e.g. --columns "id"')
|
||||
@cliutils.arg(
|
||||
'--detailed',
|
||||
metavar='<detailed>',
|
||||
default=False,
|
||||
help='Show detailed information about snapshot instances.'
|
||||
' (Default=False)')
|
||||
def do_snapshot_instance_list(cs, args):
|
||||
"""List share snapshot instances."""
|
||||
snapshot = (_find_share_snapshot(cs, args.snapshot)
|
||||
if args.snapshot else None)
|
||||
if args.columns is not None:
|
||||
list_of_keys = _split_columns(columns=args.columns)
|
||||
elif args.detailed:
|
||||
list_of_keys = ['ID', 'Snapshot ID', 'Status', 'Created_at',
|
||||
'Updated_at', 'Share_id', 'Share_instance_id',
|
||||
'Progress', 'Provider_location']
|
||||
else:
|
||||
list_of_keys = ['ID', 'Snapshot ID', 'Status']
|
||||
|
||||
instances = cs.share_snapshot_instances.list(
|
||||
detailed=args.detailed, snapshot=snapshot)
|
||||
|
||||
cliutils.print_list(instances, list_of_keys)
|
||||
|
||||
|
||||
@api_versions.wraps("2.19")
|
||||
@cliutils.arg(
|
||||
'snapshot_instance',
|
||||
metavar='<snapshot_instance>',
|
||||
help='ID of the share snapshot instance.')
|
||||
def do_snapshot_instance_show(cs, args):
|
||||
"""Show details about a share snapshot instance."""
|
||||
snapshot_instance = _find_share_snapshot_instance(
|
||||
cs, args.snapshot_instance)
|
||||
cliutils.print_dict(snapshot_instance._info)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'snapshot_instance',
|
||||
metavar='<snapshot_instance>',
|
||||
help='ID of the snapshot instance to modify.')
|
||||
@cliutils.arg(
|
||||
'--state',
|
||||
metavar='<state>',
|
||||
default='available',
|
||||
help=('Indicate which state to assign the snapshot instance. '
|
||||
'Options include available, error, creating, deleting, '
|
||||
'error_deleting. If no state is provided, available '
|
||||
'will be used.'))
|
||||
@api_versions.wraps("2.19")
|
||||
def do_snapshot_instance_reset_state(cs, args):
|
||||
"""Explicitly update the state of a share snapshot instance."""
|
||||
snapshot_instance = _find_share_snapshot_instance(
|
||||
cs, args.snapshot_instance)
|
||||
snapshot_instance.reset_state(args.state)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'share',
|
||||
metavar='<share>',
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add list, show, and reset-status admin commands for snapshot instances.
|
Loading…
Reference in New Issue
Block a user