summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2021-07-20 13:49:52 +0000
committerGerrit Code Review <review@openstack.org>2021-07-20 13:49:52 +0000
commit6ebee33bf219d42fcd0d4bf2a8c0819bddb24f3c (patch)
treeb9c7ca6fb25a85e62bbcb7e2822f72ff9667e868
parent593d3f6bd4e3cd1b23de8263e7df2aa23f793f0b (diff)
parentcb5235250cc10957b4392764b1dc3a6757784da5 (diff)
downloadpython-cinderclient-6ebee33bf219d42fcd0d4bf2a8c0819bddb24f3c.tar.gz
Merge "Remove v2 classes"
-rw-r--r--cinderclient/tests/unit/fixture_data/client.py16
-rw-r--r--cinderclient/tests/unit/test_base.py4
-rw-r--r--cinderclient/tests/unit/test_client.py1
-rw-r--r--cinderclient/tests/unit/test_utils.py4
-rw-r--r--cinderclient/tests/unit/v2/contrib/__init__.py0
-rw-r--r--cinderclient/tests/unit/v2/test_quotas.py83
-rw-r--r--cinderclient/tests/unit/v2/test_volume_transfers.py58
-rw-r--r--cinderclient/tests/unit/v3/contrib/__init__.py (renamed from cinderclient/tests/unit/v2/__init__.py)0
-rw-r--r--cinderclient/tests/unit/v3/contrib/test_list_extensions.py (renamed from cinderclient/tests/unit/v2/contrib/test_list_extensions.py)4
-rw-r--r--cinderclient/tests/unit/v3/fakes.py38
-rw-r--r--cinderclient/tests/unit/v3/fakes_base.py (renamed from cinderclient/tests/unit/v2/fakes.py)14
-rw-r--r--cinderclient/tests/unit/v3/test_auth.py (renamed from cinderclient/tests/unit/v2/test_auth.py)2
-rw-r--r--cinderclient/tests/unit/v3/test_capabilities.py (renamed from cinderclient/tests/unit/v2/test_capabilities.py)7
-rw-r--r--cinderclient/tests/unit/v3/test_cgsnapshots.py (renamed from cinderclient/tests/unit/v2/test_cgsnapshots.py)5
-rw-r--r--cinderclient/tests/unit/v3/test_consistencygroups.py (renamed from cinderclient/tests/unit/v2/test_consistencygroups.py)5
-rw-r--r--cinderclient/tests/unit/v3/test_limits.py (renamed from cinderclient/tests/unit/v2/test_limits.py)2
-rw-r--r--cinderclient/tests/unit/v3/test_pools.py (renamed from cinderclient/tests/unit/v2/test_pools.py)8
-rw-r--r--cinderclient/tests/unit/v3/test_qos.py (renamed from cinderclient/tests/unit/v2/test_qos.py)5
-rw-r--r--cinderclient/tests/unit/v3/test_quota_classes.py (renamed from cinderclient/tests/unit/v2/test_quota_classes.py)5
-rw-r--r--cinderclient/tests/unit/v3/test_quotas.py63
-rw-r--r--cinderclient/tests/unit/v3/test_services_base.py (renamed from cinderclient/tests/unit/v2/test_services.py)8
-rw-r--r--cinderclient/tests/unit/v3/test_shell.py2
-rw-r--r--cinderclient/tests/unit/v3/test_snapshot_actions.py (renamed from cinderclient/tests/unit/v2/test_snapshot_actions.py)2
-rw-r--r--cinderclient/tests/unit/v3/test_type_access.py (renamed from cinderclient/tests/unit/v2/test_type_access.py)4
-rw-r--r--cinderclient/tests/unit/v3/test_types.py (renamed from cinderclient/tests/unit/v2/test_types.py)4
-rw-r--r--cinderclient/tests/unit/v3/test_volume_backups.py21
-rw-r--r--cinderclient/tests/unit/v3/test_volume_backups_30.py (renamed from cinderclient/tests/unit/v2/test_volume_backups.py)21
-rw-r--r--cinderclient/tests/unit/v3/test_volume_encryption_types.py (renamed from cinderclient/tests/unit/v2/test_volume_encryption_types.py)4
-rw-r--r--cinderclient/tests/unit/v3/test_volumes.py19
-rw-r--r--cinderclient/tests/unit/v3/test_volumes_base.py (renamed from cinderclient/tests/unit/v2/test_volumes.py)35
-rw-r--r--cinderclient/v2/__init__.py17
-rw-r--r--cinderclient/v2/availability_zones.py41
-rw-r--r--cinderclient/v2/capabilities.py38
-rw-r--r--cinderclient/v2/cgsnapshots.py112
-rw-r--r--cinderclient/v2/client.py141
-rw-r--r--cinderclient/v2/consistencygroups.py149
-rw-r--r--cinderclient/v2/contrib/__init__.py0
-rw-r--r--cinderclient/v2/contrib/list_extensions.py44
-rw-r--r--cinderclient/v2/limits.py99
-rw-r--r--cinderclient/v2/pools.py60
-rw-r--r--cinderclient/v2/qos_specs.py155
-rw-r--r--cinderclient/v2/quota_classes.py47
-rw-r--r--cinderclient/v2/quotas.py56
-rw-r--r--cinderclient/v2/services.py80
-rw-r--r--cinderclient/v2/volume_backups.py137
-rw-r--r--cinderclient/v2/volume_backups_restore.py44
-rw-r--r--cinderclient/v2/volume_encryption_types.py104
-rw-r--r--cinderclient/v2/volume_snapshots.py39
-rw-r--r--cinderclient/v2/volume_transfers.py88
-rw-r--r--cinderclient/v2/volume_type_access.py53
-rw-r--r--cinderclient/v2/volume_types.py153
-rw-r--r--cinderclient/v3/capabilities.py22
-rw-r--r--cinderclient/v3/cgsnapshots.py96
-rw-r--r--cinderclient/v3/consistencygroups.py133
-rw-r--r--cinderclient/v3/contrib/list_extensions.py30
-rw-r--r--cinderclient/v3/limits.py84
-rw-r--r--cinderclient/v3/pools.py44
-rw-r--r--cinderclient/v3/qos_specs.py136
-rw-r--r--cinderclient/v3/quota_classes.py33
-rw-r--r--cinderclient/v3/quotas.py31
-rw-r--r--cinderclient/v3/services.py63
-rw-r--r--cinderclient/v3/shell_base.py2
-rw-r--r--cinderclient/v3/volume_backups.py91
-rw-r--r--cinderclient/v3/volume_backups_restore.py25
-rw-r--r--cinderclient/v3/volume_encryption_types.py86
-rw-r--r--cinderclient/v3/volume_snapshots.py12
-rw-r--r--cinderclient/v3/volume_transfers.py17
-rw-r--r--cinderclient/v3/volume_type_access.py38
-rw-r--r--cinderclient/v3/volumes.py20
-rw-r--r--cinderclient/v3/volumes_base.py (renamed from cinderclient/v2/volumes.py)88
-rw-r--r--doc/source/contributor/unit_tests.rst4
-rw-r--r--releasenotes/notes/drop-v2-support-e578ca21c7c6b532.yaml5
72 files changed, 1122 insertions, 2039 deletions
diff --git a/cinderclient/tests/unit/fixture_data/client.py b/cinderclient/tests/unit/fixture_data/client.py
index 2beeb90..9fe9756 100644
--- a/cinderclient/tests/unit/fixture_data/client.py
+++ b/cinderclient/tests/unit/fixture_data/client.py
@@ -13,7 +13,6 @@
from keystoneauth1 import fixture
from cinderclient.tests.unit.fixture_data import base
-from cinderclient.v2 import client as v2client
from cinderclient.v3 import client as v3client
@@ -34,21 +33,6 @@ class Base(base.Fixture):
headers=self.json_headers)
-class V2(Base):
-
- def __init__(self, *args, **kwargs):
- super(V2, self).__init__(*args, **kwargs)
-
- svc = self.token.add_service('volumev2')
- svc.add_endpoint(self.volume_url)
-
- def new_client(self):
- return v2client.Client(username='xx',
- api_key='xx',
- project_id='xx',
- auth_url=self.identity_url)
-
-
class V3(Base):
def __init__(self, *args, **kwargs):
diff --git a/cinderclient/tests/unit/test_base.py b/cinderclient/tests/unit/test_base.py
index 6ec2ca6..36503e1 100644
--- a/cinderclient/tests/unit/test_base.py
+++ b/cinderclient/tests/unit/test_base.py
@@ -22,13 +22,13 @@ from cinderclient import base
from cinderclient import exceptions
from cinderclient.tests.unit import test_utils
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
+from cinderclient.tests.unit.v3 import fakes
from cinderclient.v3 import client
from cinderclient.v3 import volumes
cs = fakes.FakeClient()
-REQUEST_ID = 'req-test-request-id'
+REQUEST_ID = test_utils.REQUEST_ID
def create_response_obj_with_header():
diff --git a/cinderclient/tests/unit/test_client.py b/cinderclient/tests/unit/test_client.py
index 1501d6f..b7cd3c6 100644
--- a/cinderclient/tests/unit/test_client.py
+++ b/cinderclient/tests/unit/test_client.py
@@ -26,7 +26,6 @@ import cinderclient.client
from cinderclient import exceptions
from cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
-import cinderclient.v2.client
@ddt.ddt
diff --git a/cinderclient/tests/unit/test_utils.py b/cinderclient/tests/unit/test_utils.py
index 1fb9433..cce4498 100644
--- a/cinderclient/tests/unit/test_utils.py
+++ b/cinderclient/tests/unit/test_utils.py
@@ -24,9 +24,9 @@ from cinderclient import base
from cinderclient import exceptions
from cinderclient import shell_utils
from cinderclient.tests.unit import utils as test_utils
-from cinderclient.tests.unit.v2 import fakes
from cinderclient import utils
+REQUEST_ID = 'req-test-request-id'
UUID = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0'
@@ -61,7 +61,7 @@ class FakeManager(base.ManagerWithFind):
raise exceptions.NotFound(resource_id)
def list(self, search_opts, **kwargs):
- return common_base.ListWithMeta(self.resources, fakes.REQUEST_ID)
+ return common_base.ListWithMeta(self.resources, REQUEST_ID)
class FakeManagerWithApi(base.Manager):
diff --git a/cinderclient/tests/unit/v2/contrib/__init__.py b/cinderclient/tests/unit/v2/contrib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/cinderclient/tests/unit/v2/contrib/__init__.py
+++ /dev/null
diff --git a/cinderclient/tests/unit/v2/test_quotas.py b/cinderclient/tests/unit/v2/test_quotas.py
deleted file mode 100644
index bb29e4d..0000000
--- a/cinderclient/tests/unit/v2/test_quotas.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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 cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-
-
-cs = fakes.FakeClient()
-
-
-class QuotaSetsTest(utils.TestCase):
-
- def test_tenant_quotas_get(self):
- tenant_id = 'test'
- quota = cs.quotas.get(tenant_id)
- cs.assert_called('GET', '/os-quota-sets/%s?usage=False' % tenant_id)
- self._assert_request_id(quota)
-
- def test_tenant_quotas_defaults(self):
- tenant_id = 'test'
- quota = cs.quotas.defaults(tenant_id)
- cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id)
- self._assert_request_id(quota)
-
- def test_update_quota(self):
- q = cs.quotas.get('test')
- q.update(volumes=2)
- q.update(snapshots=2)
- q.update(gigabytes=2000)
- q.update(backups=2)
- q.update(backup_gigabytes=2000)
- q.update(per_volume_gigabytes=100)
- cs.assert_called('PUT', '/os-quota-sets/test')
- self._assert_request_id(q)
-
- def test_refresh_quota(self):
- q = cs.quotas.get('test')
- q2 = cs.quotas.get('test')
- self.assertEqual(q.volumes, q2.volumes)
- self.assertEqual(q.snapshots, q2.snapshots)
- self.assertEqual(q.gigabytes, q2.gigabytes)
- self.assertEqual(q.backups, q2.backups)
- self.assertEqual(q.backup_gigabytes, q2.backup_gigabytes)
- self.assertEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
- q2.volumes = 0
- self.assertNotEqual(q.volumes, q2.volumes)
- q2.snapshots = 0
- self.assertNotEqual(q.snapshots, q2.snapshots)
- q2.gigabytes = 0
- self.assertNotEqual(q.gigabytes, q2.gigabytes)
- q2.backups = 0
- self.assertNotEqual(q.backups, q2.backups)
- q2.backup_gigabytes = 0
- self.assertNotEqual(q.backup_gigabytes, q2.backup_gigabytes)
- q2.per_volume_gigabytes = 0
- self.assertNotEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
- q2.get()
- self.assertEqual(q.volumes, q2.volumes)
- self.assertEqual(q.snapshots, q2.snapshots)
- self.assertEqual(q.gigabytes, q2.gigabytes)
- self.assertEqual(q.backups, q2.backups)
- self.assertEqual(q.backup_gigabytes, q2.backup_gigabytes)
- self.assertEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
- self._assert_request_id(q)
- self._assert_request_id(q2)
-
- def test_delete_quota(self):
- tenant_id = 'test'
- quota = cs.quotas.delete(tenant_id)
- cs.assert_called('DELETE', '/os-quota-sets/test')
- self._assert_request_id(quota)
diff --git a/cinderclient/tests/unit/v2/test_volume_transfers.py b/cinderclient/tests/unit/v2/test_volume_transfers.py
deleted file mode 100644
index a265cf5..0000000
--- a/cinderclient/tests/unit/v2/test_volume_transfers.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
-# 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 cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-
-
-cs = fakes.FakeClient()
-
-
-class VolumeTransfersTest(utils.TestCase):
-
- def test_create(self):
- vol = cs.transfers.create('1234')
- cs.assert_called('POST', '/os-volume-transfer')
- self._assert_request_id(vol)
-
- def test_get(self):
- transfer_id = '5678'
- vol = cs.transfers.get(transfer_id)
- cs.assert_called('GET', '/os-volume-transfer/%s' % transfer_id)
- self._assert_request_id(vol)
-
- def test_list(self):
- lst = cs.transfers.list()
- cs.assert_called('GET', '/os-volume-transfer/detail')
- self._assert_request_id(lst)
-
- def test_delete(self):
- b = cs.transfers.list()[0]
- vol = b.delete()
- cs.assert_called('DELETE', '/os-volume-transfer/5678')
- self._assert_request_id(vol)
- vol = cs.transfers.delete('5678')
- self._assert_request_id(vol)
- cs.assert_called('DELETE', '/os-volume-transfer/5678')
- vol = cs.transfers.delete(b)
- cs.assert_called('DELETE', '/os-volume-transfer/5678')
- self._assert_request_id(vol)
-
- def test_accept(self):
- transfer_id = '5678'
- auth_key = '12345'
- vol = cs.transfers.accept(transfer_id, auth_key)
- cs.assert_called('POST', '/os-volume-transfer/%s/accept' % transfer_id)
- self._assert_request_id(vol)
diff --git a/cinderclient/tests/unit/v2/__init__.py b/cinderclient/tests/unit/v3/contrib/__init__.py
index e69de29..e69de29 100644
--- a/cinderclient/tests/unit/v2/__init__.py
+++ b/cinderclient/tests/unit/v3/contrib/__init__.py
diff --git a/cinderclient/tests/unit/v2/contrib/test_list_extensions.py b/cinderclient/tests/unit/v3/contrib/test_list_extensions.py
index 4b6100f..1d7eb35 100644
--- a/cinderclient/tests/unit/v2/contrib/test_list_extensions.py
+++ b/cinderclient/tests/unit/v3/contrib/test_list_extensions.py
@@ -16,8 +16,8 @@
from cinderclient import extension
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2.contrib import list_extensions
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3.contrib import list_extensions
extensions = [
extension.Extension(list_extensions.__name__.split(".")[-1],
diff --git a/cinderclient/tests/unit/v3/fakes.py b/cinderclient/tests/unit/v3/fakes.py
index 7647fb3..7429af2 100644
--- a/cinderclient/tests/unit/v3/fakes.py
+++ b/cinderclient/tests/unit/v3/fakes.py
@@ -15,7 +15,7 @@
from datetime import datetime
from cinderclient.tests.unit import fakes
-from cinderclient.tests.unit.v2 import fakes as fake_v2
+from cinderclient.tests.unit.v3 import fakes_base
from cinderclient.v3 import client
@@ -133,7 +133,7 @@ class FakeClient(fakes.FakeClient, client.Client):
return self.client.get_volume_api_version_from_endpoint()
-class FakeHTTPClient(fake_v2.FakeHTTPClient):
+class FakeHTTPClient(fakes_base.FakeHTTPClient):
def __init__(self, **kwargs):
super(FakeHTTPClient, self).__init__()
@@ -194,6 +194,19 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
del svc['backend_state']
return (200, {}, {'services': services})
+ def put_os_services_enable(self, body, **kw):
+ return (200, {}, {'host': body['host'], 'binary': body['binary'],
+ 'status': 'enabled'})
+
+ def put_os_services_disable(self, body, **kw):
+ return (200, {}, {'host': body['host'], 'binary': body['binary'],
+ 'status': 'disabled'})
+
+ def put_os_services_disable_log_reason(self, body, **kw):
+ return (200, {}, {'host': body['host'], 'binary': body['binary'],
+ 'status': 'disabled',
+ 'disabled_reason': body['disabled_reason']})
+
#
# Clusters
#
@@ -285,7 +298,7 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
# Backups
#
def put_backups_1234(self, **kw):
- backup = fake_v2._stub_backup(
+ backup = fakes_base._stub_backup(
id='1234',
base_uri='http://localhost:8776',
tenant_id='0fa851f6668144cf9cd8c8419c1646c1')
@@ -640,10 +653,10 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
transfer2 = 'f625ec3e-13dd-4498-a22a-50afd534cc41'
return (200, {},
{'transfers': [
- fake_v2._stub_transfer_full(transfer1, base_uri,
- tenant_id),
- fake_v2._stub_transfer_full(transfer2, base_uri,
- tenant_id)]})
+ fakes_base._stub_transfer_full(transfer1, base_uri,
+ tenant_id),
+ fakes_base._stub_transfer_full(transfer2, base_uri,
+ tenant_id)]})
def get_volume_transfers_5678(self, **kw):
base_uri = 'http://localhost:8776'
@@ -651,7 +664,8 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
transfer1 = '5678'
return (200, {},
{'transfer':
- fake_v2._stub_transfer_full(transfer1, base_uri, tenant_id)})
+ fakes_base._stub_transfer_full(transfer1, base_uri,
+ tenant_id)})
def delete_volume_transfers_5678(self, **kw):
return (202, {}, None)
@@ -661,16 +675,16 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
return (202, {},
- {'transfer': fake_v2._stub_transfer(transfer1, base_uri,
- tenant_id)})
+ {'transfer': fakes_base._stub_transfer(transfer1, base_uri,
+ tenant_id)})
def post_volume_transfers_5678_accept(self, **kw):
base_uri = 'http://localhost:8776'
tenant_id = '0fa851f6668144cf9cd8c8419c1646c1'
transfer1 = '5678'
return (200, {},
- {'transfer': fake_v2._stub_transfer(transfer1, base_uri,
- tenant_id)})
+ {'transfer': fakes_base._stub_transfer(transfer1, base_uri,
+ tenant_id)})
def fake_request_get():
diff --git a/cinderclient/tests/unit/v2/fakes.py b/cinderclient/tests/unit/v3/fakes_base.py
index 700bf1e..ec75ff0 100644
--- a/cinderclient/tests/unit/v2/fakes.py
+++ b/cinderclient/tests/unit/v3/fakes_base.py
@@ -18,7 +18,6 @@ from urllib import parse as urlparse
from cinderclient import client as base_client
from cinderclient.tests.unit import fakes
import cinderclient.tests.unit.utils as utils
-from cinderclient.v2 import client
REQUEST_ID = 'req-test-request-id'
@@ -332,19 +331,6 @@ def stub_default_types():
}
-class FakeClient(fakes.FakeClient, client.Client):
-
- def __init__(self, api_version=None, *args, **kwargs):
- client.Client.__init__(self, 'username', 'password',
- 'project_id', 'auth_url',
- extensions=kwargs.get('extensions'))
- self.api_version = api_version
- self.client = FakeHTTPClient(**kwargs)
-
- def get_volume_api_version_from_endpoint(self):
- return self.client.get_volume_api_version_from_endpoint()
-
-
class FakeHTTPClient(base_client.HTTPClient):
def __init__(self, version_header=None, **kwargs):
diff --git a/cinderclient/tests/unit/v2/test_auth.py b/cinderclient/tests/unit/v3/test_auth.py
index 5d7a4bc..3e5e708 100644
--- a/cinderclient/tests/unit/v2/test_auth.py
+++ b/cinderclient/tests/unit/v3/test_auth.py
@@ -21,7 +21,7 @@ import requests
from cinderclient import exceptions
from cinderclient.tests.unit import utils
-from cinderclient.v2 import client
+from cinderclient.v3 import client
class AuthenticateAgainstKeystoneTests(utils.TestCase):
diff --git a/cinderclient/tests/unit/v2/test_capabilities.py b/cinderclient/tests/unit/v3/test_capabilities.py
index 98d8d71..9f8c4c6 100644
--- a/cinderclient/tests/unit/v2/test_capabilities.py
+++ b/cinderclient/tests/unit/v3/test_capabilities.py
@@ -13,11 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2.capabilities import Capabilities
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3.capabilities import Capabilities
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
FAKE_CAPABILITY = {
'namespace': 'OS::Storage::Capabilities::fake',
diff --git a/cinderclient/tests/unit/v2/test_cgsnapshots.py b/cinderclient/tests/unit/v3/test_cgsnapshots.py
index 3ebef9e..5f0cec7 100644
--- a/cinderclient/tests/unit/v2/test_cgsnapshots.py
+++ b/cinderclient/tests/unit/v3/test_cgsnapshots.py
@@ -14,11 +14,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
+from cinderclient.tests.unit.v3 import fakes
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class cgsnapshotsTest(utils.TestCase):
diff --git a/cinderclient/tests/unit/v2/test_consistencygroups.py b/cinderclient/tests/unit/v3/test_consistencygroups.py
index a695fe9..d265aab 100644
--- a/cinderclient/tests/unit/v2/test_consistencygroups.py
+++ b/cinderclient/tests/unit/v3/test_consistencygroups.py
@@ -14,10 +14,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
+from cinderclient.tests.unit.v3 import fakes
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class ConsistencygroupsTest(utils.TestCase):
diff --git a/cinderclient/tests/unit/v2/test_limits.py b/cinderclient/tests/unit/v3/test_limits.py
index d8fbdfe..a42f770 100644
--- a/cinderclient/tests/unit/v2/test_limits.py
+++ b/cinderclient/tests/unit/v3/test_limits.py
@@ -18,7 +18,7 @@ from unittest import mock
import ddt
from cinderclient.tests.unit import utils
-from cinderclient.v2 import limits
+from cinderclient.v3 import limits
REQUEST_ID = 'req-test-request-id'
diff --git a/cinderclient/tests/unit/v2/test_pools.py b/cinderclient/tests/unit/v3/test_pools.py
index e909871..6af9057 100644
--- a/cinderclient/tests/unit/v2/test_pools.py
+++ b/cinderclient/tests/unit/v3/test_pools.py
@@ -13,11 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2.pools import Pool
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3.pools import Pool
-cs = fakes.FakeClient()
+
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class PoolsTest(utils.TestCase):
diff --git a/cinderclient/tests/unit/v2/test_qos.py b/cinderclient/tests/unit/v3/test_qos.py
index 809a719..f613390 100644
--- a/cinderclient/tests/unit/v2/test_qos.py
+++ b/cinderclient/tests/unit/v3/test_qos.py
@@ -13,11 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
+from cinderclient.tests.unit.v3 import fakes
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class QoSSpecsTest(utils.TestCase):
diff --git a/cinderclient/tests/unit/v2/test_quota_classes.py b/cinderclient/tests/unit/v3/test_quota_classes.py
index 4182fdf..29f4d0c 100644
--- a/cinderclient/tests/unit/v2/test_quota_classes.py
+++ b/cinderclient/tests/unit/v3/test_quota_classes.py
@@ -13,11 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
+from cinderclient.tests.unit.v3 import fakes
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class QuotaClassSetsTest(utils.TestCase):
diff --git a/cinderclient/tests/unit/v3/test_quotas.py b/cinderclient/tests/unit/v3/test_quotas.py
index fbabb47..e67c477 100644
--- a/cinderclient/tests/unit/v3/test_quotas.py
+++ b/cinderclient/tests/unit/v3/test_quotas.py
@@ -13,17 +13,78 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
class QuotaSetsTest(utils.TestCase):
+ def test_tenant_quotas_get(self):
+ tenant_id = 'test'
+ quota = cs.quotas.get(tenant_id)
+ cs.assert_called('GET', '/os-quota-sets/%s?usage=False' % tenant_id)
+ self._assert_request_id(quota)
+
+ def test_tenant_quotas_defaults(self):
+ tenant_id = 'test'
+ quota = cs.quotas.defaults(tenant_id)
+ cs.assert_called('GET', '/os-quota-sets/%s/defaults' % tenant_id)
+ self._assert_request_id(quota)
+
+ def test_update_quota(self):
+ q = cs.quotas.get('test')
+ q.update(volumes=2)
+ q.update(snapshots=2)
+ q.update(gigabytes=2000)
+ q.update(backups=2)
+ q.update(backup_gigabytes=2000)
+ q.update(per_volume_gigabytes=100)
+ cs.assert_called('PUT', '/os-quota-sets/test')
+ self._assert_request_id(q)
+
def test_update_quota_with_skip_(self):
q = cs.quotas.get('test')
q.update(skip_validation=False)
cs.assert_called('PUT', '/os-quota-sets/test?skip_validation=False')
self._assert_request_id(q)
+
+ def test_refresh_quota(self):
+ q = cs.quotas.get('test')
+ q2 = cs.quotas.get('test')
+ self.assertEqual(q.volumes, q2.volumes)
+ self.assertEqual(q.snapshots, q2.snapshots)
+ self.assertEqual(q.gigabytes, q2.gigabytes)
+ self.assertEqual(q.backups, q2.backups)
+ self.assertEqual(q.backup_gigabytes, q2.backup_gigabytes)
+ self.assertEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
+ q2.volumes = 0
+ self.assertNotEqual(q.volumes, q2.volumes)
+ q2.snapshots = 0
+ self.assertNotEqual(q.snapshots, q2.snapshots)
+ q2.gigabytes = 0
+ self.assertNotEqual(q.gigabytes, q2.gigabytes)
+ q2.backups = 0
+ self.assertNotEqual(q.backups, q2.backups)
+ q2.backup_gigabytes = 0
+ self.assertNotEqual(q.backup_gigabytes, q2.backup_gigabytes)
+ q2.per_volume_gigabytes = 0
+ self.assertNotEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
+ q2.get()
+ self.assertEqual(q.volumes, q2.volumes)
+ self.assertEqual(q.snapshots, q2.snapshots)
+ self.assertEqual(q.gigabytes, q2.gigabytes)
+ self.assertEqual(q.backups, q2.backups)
+ self.assertEqual(q.backup_gigabytes, q2.backup_gigabytes)
+ self.assertEqual(q.per_volume_gigabytes, q2.per_volume_gigabytes)
+ self._assert_request_id(q)
+ self._assert_request_id(q2)
+
+ def test_delete_quota(self):
+ tenant_id = 'test'
+ quota = cs.quotas.delete(tenant_id)
+ cs.assert_called('DELETE', '/os-quota-sets/test')
+ self._assert_request_id(quota)
diff --git a/cinderclient/tests/unit/v2/test_services.py b/cinderclient/tests/unit/v3/test_services_base.py
index d355d7f..711a536 100644
--- a/cinderclient/tests/unit/v2/test_services.py
+++ b/cinderclient/tests/unit/v3/test_services_base.py
@@ -13,15 +13,17 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2 import services
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3 import services
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_version=api_versions.APIVersion('3.0'))
class ServicesTest(utils.TestCase):
+ """Tests for v3.0 behavior"""
def test_list_services(self):
svs = cs.services.list()
diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py
index 756f512..a5b76fe 100644
--- a/cinderclient/tests/unit/v3/test_shell.py
+++ b/cinderclient/tests/unit/v3/test_shell.py
@@ -1745,7 +1745,7 @@ class ShellTest(utils.TestCase):
)
@ddt.unpack
@mock.patch('cinderclient.utils.print_dict')
- @mock.patch('cinderclient.tests.unit.v2.fakes._stub_restore')
+ @mock.patch('cinderclient.tests.unit.v3.fakes_base._stub_restore')
def test_do_backup_restore(self,
mock_stub_restore,
mock_print_dict,
diff --git a/cinderclient/tests/unit/v2/test_snapshot_actions.py b/cinderclient/tests/unit/v3/test_snapshot_actions.py
index 61fd0d0..8d2b23a 100644
--- a/cinderclient/tests/unit/v2/test_snapshot_actions.py
+++ b/cinderclient/tests/unit/v3/test_snapshot_actions.py
@@ -20,7 +20,7 @@ from cinderclient.tests.unit import utils
class SnapshotActionsTest(utils.FixturedTestCase):
- client_fixture_class = client.V2
+ client_fixture_class = client.V3
data_fixture_class = snapshots.Fixture
def test_update_snapshot_status(self):
diff --git a/cinderclient/tests/unit/v2/test_type_access.py b/cinderclient/tests/unit/v3/test_type_access.py
index d904c1d..5b2dbb3 100644
--- a/cinderclient/tests/unit/v2/test_type_access.py
+++ b/cinderclient/tests/unit/v3/test_type_access.py
@@ -15,8 +15,8 @@
# under the License.
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2 import volume_type_access
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3 import volume_type_access
cs = fakes.FakeClient()
diff --git a/cinderclient/tests/unit/v2/test_types.py b/cinderclient/tests/unit/v3/test_types.py
index cf13723..fdbd323 100644
--- a/cinderclient/tests/unit/v2/test_types.py
+++ b/cinderclient/tests/unit/v3/test_types.py
@@ -15,8 +15,8 @@
# under the License.
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2 import volume_types
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3 import volume_types
cs = fakes.FakeClient()
diff --git a/cinderclient/tests/unit/v3/test_volume_backups.py b/cinderclient/tests/unit/v3/test_volume_backups.py
index faa0185..3be6328 100644
--- a/cinderclient/tests/unit/v3/test_volume_backups.py
+++ b/cinderclient/tests/unit/v3/test_volume_backups.py
@@ -17,6 +17,7 @@ from cinderclient import api_versions
from cinderclient import exceptions as exc
from cinderclient.tests.unit import utils
from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3 import volume_backups_restore
class VolumesTest(utils.TestCase):
@@ -35,3 +36,23 @@ class VolumesTest(utils.TestCase):
b = cs.backups.get('1234')
self.assertRaises(exc.VersionNotFoundForAPIMethod,
b.update, name='new-name')
+
+ def test_restore(self):
+ cs = fakes.FakeClient(api_version=api_versions.APIVersion('3.0'))
+ backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
+ info = cs.restores.restore(backup_id)
+ cs.assert_called('POST', '/backups/%s/restore' % backup_id)
+ self.assertIsInstance(info,
+ volume_backups_restore.VolumeBackupsRestore)
+ self._assert_request_id(info)
+
+ def test_restore_with_name(self):
+ cs = fakes.FakeClient(api_version=api_versions.APIVersion('3.0'))
+ backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
+ name = 'restore_vol'
+ info = cs.restores.restore(backup_id, name=name)
+ expected_body = {'restore': {'volume_id': None, 'name': name}}
+ cs.assert_called('POST', '/backups/%s/restore' % backup_id,
+ body=expected_body)
+ self.assertIsInstance(info,
+ volume_backups_restore.VolumeBackupsRestore)
diff --git a/cinderclient/tests/unit/v2/test_volume_backups.py b/cinderclient/tests/unit/v3/test_volume_backups_30.py
index 700c440..daf517c 100644
--- a/cinderclient/tests/unit/v2/test_volume_backups.py
+++ b/cinderclient/tests/unit/v3/test_volume_backups_30.py
@@ -14,8 +14,7 @@
# under the License.
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2 import volume_backups_restore
+from cinderclient.tests.unit.v3 import fakes
cs = fakes.FakeClient()
@@ -118,24 +117,6 @@ class VolumeBackupsTest(utils.TestCase):
'/backups/76a17945-3c6f-435c-975b-b5685db10b62')
self._assert_request_id(del_back)
- def test_restore(self):
- backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
- info = cs.restores.restore(backup_id)
- cs.assert_called('POST', '/backups/%s/restore' % backup_id)
- self.assertIsInstance(info,
- volume_backups_restore.VolumeBackupsRestore)
- self._assert_request_id(info)
-
- def test_restore_with_name(self):
- backup_id = '76a17945-3c6f-435c-975b-b5685db10b62'
- name = 'restore_vol'
- info = cs.restores.restore(backup_id, name=name)
- expected_body = {'restore': {'volume_id': None, 'name': name}}
- cs.assert_called('POST', '/backups/%s/restore' % backup_id,
- body=expected_body)
- self.assertIsInstance(info,
- volume_backups_restore.VolumeBackupsRestore)
-
def test_reset_state(self):
b = cs.backups.list()[0]
api = '/backups/76a17945-3c6f-435c-975b-b5685db10b62/action'
diff --git a/cinderclient/tests/unit/v2/test_volume_encryption_types.py b/cinderclient/tests/unit/v3/test_volume_encryption_types.py
index 1bbf537..9e38d51 100644
--- a/cinderclient/tests/unit/v2/test_volume_encryption_types.py
+++ b/cinderclient/tests/unit/v3/test_volume_encryption_types.py
@@ -14,8 +14,8 @@
# under the License.
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2.volume_encryption_types import VolumeEncryptionType
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3.volume_encryption_types import VolumeEncryptionType
cs = fakes.FakeClient()
diff --git a/cinderclient/tests/unit/v3/test_volumes.py b/cinderclient/tests/unit/v3/test_volumes.py
index e5b3f21..c733a09 100644
--- a/cinderclient/tests/unit/v3/test_volumes.py
+++ b/cinderclient/tests/unit/v3/test_volumes.py
@@ -87,6 +87,25 @@ class VolumesTest(utils.TestCase):
cs.assert_called('POST', '/volumes', body=expected)
self._assert_request_id(vol)
+ def test_create_volume_with_hint(self):
+ cs = fakes.FakeClient(api_versions.APIVersion('3.0'))
+ vol = cs.volumes.create(1, scheduler_hints='uuid')
+ expected = {'volume': {'description': None,
+ 'availability_zone': None,
+ 'source_volid': None,
+ 'snapshot_id': None,
+ 'size': 1,
+ 'name': None,
+ 'imageRef': None,
+ 'volume_type': None,
+ 'metadata': {},
+ 'consistencygroup_id': None,
+ 'backup_id': None,
+ },
+ 'OS-SCH-HNT:scheduler_hints': 'uuid'}
+ cs.assert_called('POST', '/volumes', body=expected)
+ self._assert_request_id(vol)
+
@ddt.data((False, '/volumes/summary'),
(True, '/volumes/summary?all_tenants=True'))
def test_volume_summary(self, all_tenants_input):
diff --git a/cinderclient/tests/unit/v2/test_volumes.py b/cinderclient/tests/unit/v3/test_volumes_base.py
index e4f9e32..cca808a 100644
--- a/cinderclient/tests/unit/v2/test_volumes.py
+++ b/cinderclient/tests/unit/v3/test_volumes_base.py
@@ -15,14 +15,16 @@
# License for the specific language governing permissions and limitations
# under the License.
+from cinderclient import api_versions
from cinderclient.tests.unit import utils
-from cinderclient.tests.unit.v2 import fakes
-from cinderclient.v2.volumes import Volume
+from cinderclient.tests.unit.v3 import fakes
+from cinderclient.v3.volumes import Volume
-cs = fakes.FakeClient()
+cs = fakes.FakeClient(api_version=api_versions.APIVersion('3.0'))
class VolumesTest(utils.TestCase):
+ """Block Storage API v3.0"""
def test_list_volumes_with_marker_limit(self):
lst = cs.volumes.list(marker=1234, limit=2)
@@ -58,6 +60,11 @@ class VolumesTest(utils.TestCase):
self._assert_request_id(volumes)
cs.client.osapi_max_limit = 1000
+ def test_create_volume(self):
+ vol = cs.volumes.create(1)
+ cs.assert_called('POST', '/volumes')
+ self._assert_request_id(vol)
+
def test_delete_volume(self):
v = cs.volumes.list()[0]
del_v = v.delete()
@@ -70,28 +77,6 @@ class VolumesTest(utils.TestCase):
cs.assert_called('DELETE', '/volumes/1234')
self._assert_request_id(del_v)
- def test_create_volume(self):
- vol = cs.volumes.create(1)
- cs.assert_called('POST', '/volumes')
- self._assert_request_id(vol)
-
- def test_create_volume_with_hint(self):
- vol = cs.volumes.create(1, scheduler_hints='uuid')
- expected = {'volume': {'description': None,
- 'availability_zone': None,
- 'source_volid': None,
- 'snapshot_id': None,
- 'size': 1,
- 'name': None,
- 'imageRef': None,
- 'volume_type': None,
- 'metadata': {},
- 'consistencygroup_id': None,
- },
- 'OS-SCH-HNT:scheduler_hints': 'uuid'}
- cs.assert_called('POST', '/volumes', body=expected)
- self._assert_request_id(vol)
-
def test_attach(self):
v = cs.volumes.get('1234')
self._assert_request_id(v)
diff --git a/cinderclient/v2/__init__.py b/cinderclient/v2/__init__.py
deleted file mode 100644
index 325460e..0000000
--- a/cinderclient/v2/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-#
-# 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 cinderclient.v2.client import Client # noqa
diff --git a/cinderclient/v2/availability_zones.py b/cinderclient/v2/availability_zones.py
deleted file mode 100644
index 6503c12..0000000
--- a/cinderclient/v2/availability_zones.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2011-2013 OpenStack Foundation
-# Copyright 2013 IBM Corp.
-# 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.
-"""Availability Zone interface (v2 extension)"""
-
-from cinderclient import base
-
-
-class AvailabilityZone(base.Resource):
- NAME_ATTR = 'display_name'
-
- def __repr__(self):
- return "<AvailabilityZone: %s>" % self.zoneName
-
-
-class AvailabilityZoneManager(base.ManagerWithFind):
- """Manage :class:`AvailabilityZone` resources."""
- resource_class = AvailabilityZone
-
- def list(self, detailed=False):
- """Lists all availability zones.
-
- :rtype: list of :class:`AvailabilityZone`
- """
- if detailed is True:
- return self._list("/os-availability-zone/detail",
- "availabilityZoneInfo")
- else:
- return self._list("/os-availability-zone", "availabilityZoneInfo")
diff --git a/cinderclient/v2/capabilities.py b/cinderclient/v2/capabilities.py
deleted file mode 100644
index 2045f02..0000000
--- a/cinderclient/v2/capabilities.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (c) 2015 Hitachi Data Systems, 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.
-
-"""Capabilities interface (v2 extension)"""
-
-from cinderclient import base
-
-
-class Capabilities(base.Resource):
- NAME_ATTR = 'name'
-
- def __repr__(self):
- return "<Capabilities: %s>" % self._info.get('namespace')
-
-
-class CapabilitiesManager(base.Manager):
- """Manage :class:`Capabilities` resources."""
- resource_class = Capabilities
-
- def get(self, host):
- """Show backend volume stats and properties.
-
- :param host: Specified backend to obtain volume stats and properties.
- :rtype: :class:`Capabilities`
- """
- return self._get('/capabilities/%s' % host, None)
diff --git a/cinderclient/v2/cgsnapshots.py b/cinderclient/v2/cgsnapshots.py
deleted file mode 100644
index 04444e2..0000000
--- a/cinderclient/v2/cgsnapshots.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright (C) 2012 - 2014 EMC Corporation.
-# 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.
-
-"""cgsnapshot interface (v2 extension)."""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-from cinderclient import utils
-
-
-class Cgsnapshot(base.Resource):
- """A cgsnapshot is snapshot of a consistency group."""
- def __repr__(self):
- return "<cgsnapshot: %s>" % self.id
-
- def delete(self):
- """Delete this cgsnapshot."""
- return self.manager.delete(self)
-
- def update(self, **kwargs):
- """Update the name or description for this cgsnapshot."""
- return self.manager.update(self, **kwargs)
-
-
-class CgsnapshotManager(base.ManagerWithFind):
- """Manage :class:`Cgsnapshot` resources."""
- resource_class = Cgsnapshot
-
- def create(self, consistencygroup_id, name=None, description=None,
- user_id=None,
- project_id=None):
- """Creates a cgsnapshot.
-
- :param consistencygroup: Name or uuid of a consistency group
- :param name: Name of the cgsnapshot
- :param description: Description of the cgsnapshot
- :param user_id: User id derived from context
- :param project_id: Project id derived from context
- :rtype: :class:`Cgsnapshot`
- """
-
- body = {'cgsnapshot': {'consistencygroup_id': consistencygroup_id,
- 'name': name,
- 'description': description,
- 'user_id': user_id,
- 'project_id': project_id,
- 'status': "creating",
- }}
-
- return self._create('/cgsnapshots', body, 'cgsnapshot')
-
- def get(self, cgsnapshot_id):
- """Get a cgsnapshot.
-
- :param cgsnapshot_id: The ID of the cgsnapshot to get.
- :rtype: :class:`Cgsnapshot`
- """
- return self._get("/cgsnapshots/%s" % cgsnapshot_id, "cgsnapshot")
-
- def list(self, detailed=True, search_opts=None):
- """Lists all cgsnapshots.
-
- :rtype: list of :class:`Cgsnapshot`
- """
- query_string = utils.build_query_param(search_opts)
-
- detail = ""
- if detailed:
- detail = "/detail"
-
- return self._list("/cgsnapshots%s%s" % (detail, query_string),
- "cgsnapshots")
-
- def delete(self, cgsnapshot):
- """Delete a cgsnapshot.
-
- :param cgsnapshot: The :class:`Cgsnapshot` to delete.
- """
- return self._delete("/cgsnapshots/%s" % base.getid(cgsnapshot))
-
- def update(self, cgsnapshot, **kwargs):
- """Update the name or description for a cgsnapshot.
-
- :param cgsnapshot: The :class:`Cgsnapshot` to update.
- """
- if not kwargs:
- return
-
- body = {"cgsnapshot": kwargs}
-
- return self._update("/cgsnapshots/%s" % base.getid(cgsnapshot), body)
-
- def _action(self, action, cgsnapshot, info=None, **kwargs):
- """Perform a cgsnapshot "action."
- """
- body = {action: info}
- self.run_hooks('modify_body_for_action', body, **kwargs)
- url = '/cgsnapshots/%s/action' % base.getid(cgsnapshot)
- resp, body = self.api.client.post(url, body=body)
- return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v2/client.py b/cinderclient/v2/client.py
deleted file mode 100644
index a111c51..0000000
--- a/cinderclient/v2/client.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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 logging
-
-from cinderclient import api_versions
-from cinderclient import client
-from cinderclient.v2 import availability_zones
-from cinderclient.v2 import capabilities
-from cinderclient.v2 import cgsnapshots
-from cinderclient.v2 import consistencygroups
-from cinderclient.v2 import limits
-from cinderclient.v2 import pools
-from cinderclient.v2 import qos_specs
-from cinderclient.v2 import quota_classes
-from cinderclient.v2 import quotas
-from cinderclient.v2 import services
-from cinderclient.v2 import volume_backups
-from cinderclient.v2 import volume_backups_restore
-from cinderclient.v2 import volume_encryption_types
-from cinderclient.v2 import volume_snapshots
-from cinderclient.v2 import volume_transfers
-from cinderclient.v2 import volume_type_access
-from cinderclient.v2 import volume_types
-from cinderclient.v2 import volumes
-
-
-class Client(object):
- """Top-level object to access the OpenStack Volume API.
-
- Create an instance with your creds::
-
- >>> client = Client(USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)
-
- Then call methods on its managers::
-
- >>> client.volumes.list()
- ...
- """
-
- def __init__(self, username=None, api_key=None, project_id=None,
- auth_url='', insecure=False, timeout=None, tenant_id=None,
- proxy_tenant_id=None, proxy_token=None, region_name=None,
- endpoint_type='publicURL', extensions=None,
- service_type='volumev2', service_name=None,
- volume_service_name=None, os_endpoint=None, retries=0,
- http_log_debug=False, cacert=None, cert=None,
- auth_system='keystone', auth_plugin=None, session=None,
- api_version=None, logger=None, **kwargs):
- # FIXME(comstud): Rename the api_key argument above when we
- # know it's not being used as keyword argument
- password = api_key
- self.version = '2.0'
- self.limits = limits.LimitsManager(self)
-
- # extensions
- self.volumes = volumes.VolumeManager(self)
- self.volume_snapshots = volume_snapshots.SnapshotManager(self)
- self.volume_types = volume_types.VolumeTypeManager(self)
- self.volume_type_access = \
- volume_type_access.VolumeTypeAccessManager(self)
- self.volume_encryption_types = \
- volume_encryption_types.VolumeEncryptionTypeManager(self)
- self.qos_specs = qos_specs.QoSSpecsManager(self)
- self.quota_classes = quota_classes.QuotaClassSetManager(self)
- self.quotas = quotas.QuotaSetManager(self)
- self.backups = volume_backups.VolumeBackupManager(self)
- self.restores = volume_backups_restore.VolumeBackupRestoreManager(self)
- self.transfers = volume_transfers.VolumeTransferManager(self)
- self.services = services.ServiceManager(self)
- self.consistencygroups = consistencygroups.\
- ConsistencygroupManager(self)
- self.cgsnapshots = cgsnapshots.CgsnapshotManager(self)
- self.availability_zones = \
- availability_zones.AvailabilityZoneManager(self)
- self.pools = pools.PoolManager(self)
- self.capabilities = capabilities.CapabilitiesManager(self)
- self.api_version = api_version or api_versions.APIVersion(self.version)
-
- # Add in any extensions...
- if extensions:
- for extension in extensions:
- if extension.manager_class:
- setattr(self, extension.name,
- extension.manager_class(self))
-
- if not logger:
- logger = logging.getLogger(__name__)
-
- self.client = client._construct_http_client(
- username=username,
- password=password,
- project_id=project_id,
- auth_url=auth_url,
- insecure=insecure,
- timeout=timeout,
- tenant_id=tenant_id,
- proxy_tenant_id=tenant_id,
- proxy_token=proxy_token,
- region_name=region_name,
- endpoint_type=endpoint_type,
- service_type=service_type,
- service_name=service_name,
- volume_service_name=volume_service_name,
- os_endpoint=os_endpoint,
- retries=retries,
- http_log_debug=http_log_debug,
- cacert=cacert,
- cert=cert,
- auth_system=auth_system,
- auth_plugin=auth_plugin,
- session=session,
- api_version=self.api_version,
- logger=logger,
- **kwargs)
-
- def authenticate(self):
- """Authenticate against the server.
-
- Normally this is called automatically when you first access the API,
- but you can call this method to force authentication right now.
-
- Returns on success; raises :exc:`exceptions.Unauthorized` if the
- credentials are wrong.
- """
- self.client.authenticate()
-
- def get_volume_api_version_from_endpoint(self):
- return self.client.get_volume_api_version_from_endpoint()
diff --git a/cinderclient/v2/consistencygroups.py b/cinderclient/v2/consistencygroups.py
deleted file mode 100644
index d5e5bbf..0000000
--- a/cinderclient/v2/consistencygroups.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# Copyright (C) 2012 - 2014 EMC Corporation.
-# 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.
-
-"""Consistencygroup interface (v2 extension)."""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-from cinderclient import utils
-
-
-class Consistencygroup(base.Resource):
- """A Consistencygroup of volumes."""
- def __repr__(self):
- return "<Consistencygroup: %s>" % self.id
-
- def delete(self, force='False'):
- """Delete this consistency group."""
- return self.manager.delete(self, force)
-
- def update(self, **kwargs):
- """Update the name or description for this consistency group."""
- return self.manager.update(self, **kwargs)
-
-
-class ConsistencygroupManager(base.ManagerWithFind):
- """Manage :class:`Consistencygroup` resources."""
- resource_class = Consistencygroup
-
- def create(self, volume_types, name=None,
- description=None, user_id=None,
- project_id=None, availability_zone=None):
- """Creates a consistency group.
-
- :param name: Name of the ConsistencyGroup
- :param description: Description of the ConsistencyGroup
- :param volume_types: Types of volume
- :param user_id: User id derived from context
- :param project_id: Project id derived from context
- :param availability_zone: Availability Zone to use
- :rtype: :class:`Consistencygroup`
- """
-
- body = {'consistencygroup': {'name': name,
- 'description': description,
- 'volume_types': volume_types,
- 'user_id': user_id,
- 'project_id': project_id,
- 'availability_zone': availability_zone,
- 'status': "creating",
- }}
-
- return self._create('/consistencygroups', body, 'consistencygroup')
-
- def create_from_src(self, cgsnapshot_id, source_cgid, name=None,
- description=None, user_id=None,
- project_id=None):
- """Creates a consistency group from a cgsnapshot or a source CG.
-
- :param cgsnapshot_id: UUID of a CGSnapshot
- :param source_cgid: UUID of a source CG
- :param name: Name of the ConsistencyGroup
- :param description: Description of the ConsistencyGroup
- :param user_id: User id derived from context
- :param project_id: Project id derived from context
- :rtype: A dictionary containing Consistencygroup metadata
- """
- body = {'consistencygroup-from-src': {'name': name,
- 'description': description,
- 'cgsnapshot_id': cgsnapshot_id,
- 'source_cgid': source_cgid,
- 'user_id': user_id,
- 'project_id': project_id,
- 'status': "creating",
- }}
-
- self.run_hooks('modify_body_for_update', body,
- 'consistencygroup-from-src')
- resp, body = self.api.client.post(
- "/consistencygroups/create_from_src", body=body)
- return common_base.DictWithMeta(body['consistencygroup'], resp)
-
- def get(self, group_id):
- """Get a consistency group.
-
- :param group_id: The ID of the consistency group to get.
- :rtype: :class:`Consistencygroup`
- """
- return self._get("/consistencygroups/%s" % group_id,
- "consistencygroup")
-
- def list(self, detailed=True, search_opts=None):
- """Lists all consistency groups.
-
- :rtype: list of :class:`Consistencygroup`
- """
-
- query_string = utils.build_query_param(search_opts)
-
- detail = ""
- if detailed:
- detail = "/detail"
-
- return self._list("/consistencygroups%s%s" % (detail, query_string),
- "consistencygroups")
-
- def delete(self, consistencygroup, force=False):
- """Delete a consistency group.
-
- :param Consistencygroup: The :class:`Consistencygroup` to delete.
- """
- body = {'consistencygroup': {'force': force}}
- self.run_hooks('modify_body_for_action', body, 'consistencygroup')
- url = '/consistencygroups/%s/delete' % base.getid(consistencygroup)
- resp, body = self.api.client.post(url, body=body)
- return common_base.TupleWithMeta((resp, body), resp)
-
- def update(self, consistencygroup, **kwargs):
- """Update the name or description for a consistency group.
-
- :param Consistencygroup: The :class:`Consistencygroup` to update.
- """
- if not kwargs:
- return
-
- body = {"consistencygroup": kwargs}
-
- return self._update("/consistencygroups/%s" %
- base.getid(consistencygroup), body)
-
- def _action(self, action, consistencygroup, info=None, **kwargs):
- """Perform a consistency group "action."
- """
- body = {action: info}
- self.run_hooks('modify_body_for_action', body, **kwargs)
- url = '/consistencygroups/%s/action' % base.getid(consistencygroup)
- resp, body = self.api.client.post(url, body=body)
- return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v2/contrib/__init__.py b/cinderclient/v2/contrib/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/cinderclient/v2/contrib/__init__.py
+++ /dev/null
diff --git a/cinderclient/v2/contrib/list_extensions.py b/cinderclient/v2/contrib/list_extensions.py
deleted file mode 100644
index 937d34b..0000000
--- a/cinderclient/v2/contrib/list_extensions.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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 cinderclient import base
-from cinderclient import utils
-
-
-class ListExtResource(base.Resource):
- @property
- def summary(self):
- descr = self.description.strip()
- if not descr:
- return '??'
- lines = descr.split("\n")
- if len(lines) == 1:
- return lines[0]
- else:
- return lines[0] + "..."
-
-
-class ListExtManager(base.Manager):
- resource_class = ListExtResource
-
- def show_all(self):
- return self._list("/extensions", 'extensions')
-
-
-def do_list_extensions(client, _args):
- """Lists all available os-api extensions."""
- extensions = client.list_extensions.show_all()
- fields = ["Name", "Summary", "Alias", "Updated"]
- utils.print_list(extensions, fields)
diff --git a/cinderclient/v2/limits.py b/cinderclient/v2/limits.py
deleted file mode 100644
index dd1666d..0000000
--- a/cinderclient/v2/limits.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-#
-# 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.
-"""Limits interface (v2 extension)"""
-
-from cinderclient import base
-from cinderclient import utils
-
-
-class Limits(base.Resource):
- """A collection of RateLimit and AbsoluteLimit objects."""
-
- def __repr__(self):
- return "<Limits>"
-
- @property
- def absolute(self):
- for (name, value) in list(self._info['absolute'].items()):
- yield AbsoluteLimit(name, value)
-
- @property
- def rate(self):
- for group in self._info['rate']:
- uri = group['uri']
- regex = group['regex']
- for rate in group['limit']:
- yield RateLimit(rate['verb'], uri, regex, rate['value'],
- rate['remaining'], rate['unit'],
- rate['next-available'])
-
-
-class RateLimit(object):
- """Data model that represents a flattened view of a single rate limit."""
-
- def __init__(self, verb, uri, regex, value, remain,
- unit, next_available):
- self.verb = verb
- self.uri = uri
- self.regex = regex
- self.value = value
- self.remain = remain
- self.unit = unit
- self.next_available = next_available
-
- def __eq__(self, other):
- return self.uri == other.uri \
- and self.regex == other.regex \
- and self.value == other.value \
- and self.verb == other.verb \
- and self.remain == other.remain \
- and self.unit == other.unit \
- and self.next_available == other.next_available
-
- def __repr__(self):
- return "<RateLimit: method=%s uri=%s>" % (self.verb, self.uri)
-
-
-class AbsoluteLimit(object):
- """Data model that represents a single absolute limit."""
-
- def __init__(self, name, value):
- self.name = name
- self.value = value
-
- def __eq__(self, other):
- return self.value == other.value and self.name == other.name
-
- def __repr__(self):
- return "<AbsoluteLimit: name=%s>" % (self.name)
-
-
-class LimitsManager(base.Manager):
- """Manager object used to interact with limits resource."""
-
- resource_class = Limits
-
- def get(self, tenant_id=None):
- """Get a specific extension.
-
- :rtype: :class:`Limits`
- """
- opts = {}
- if tenant_id:
- opts['tenant_id'] = tenant_id
-
- query_string = utils.build_query_param(opts)
-
- return self._get("/limits%s" % query_string, "limits")
diff --git a/cinderclient/v2/pools.py b/cinderclient/v2/pools.py
deleted file mode 100644
index 2a55e77..0000000
--- a/cinderclient/v2/pools.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2015 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""Pools interface (v2 extension)"""
-
-from cinderclient import base
-
-
-class Pool(base.Resource):
- NAME_ATTR = 'name'
-
- def __repr__(self):
- return "<Pool: %s>" % self.name
-
-
-class PoolManager(base.Manager):
- """Manage :class:`Pool` resources."""
- resource_class = Pool
-
- def list(self, detailed=False):
- """Lists all
-
- :rtype: list of :class:`Pool`
- """
- if detailed is True:
- pools = self._list("/scheduler-stats/get_pools?detail=True",
- "pools")
- # Other than the name, all of the pool data is buried below in
- # a 'capabilities' dictionary. In order to be consistent with the
- # get-pools command line, these elements are moved up a level to
- # be attributes of the pool itself.
- for pool in pools:
- if hasattr(pool, 'capabilities'):
- for k, v in pool.capabilities.items():
- setattr(pool, k, v)
-
- # Remove the capabilities dictionary since all of its
- # elements have been copied up to the containing pool
- del pool.capabilities
- return pools
- else:
- pools = self._list("/scheduler-stats/get_pools", "pools")
-
- # avoid cluttering the basic pool list with capabilities dict
- for pool in pools:
- if hasattr(pool, 'capabilities'):
- del pool.capabilities
- return pools
diff --git a/cinderclient/v2/qos_specs.py b/cinderclient/v2/qos_specs.py
deleted file mode 100644
index 147132a..0000000
--- a/cinderclient/v2/qos_specs.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# Copyright (c) 2013 eBay Inc.
-# Copyright (c) OpenStack Foundation
-#
-# 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.
-
-"""
-QoS Specs interface.
-"""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-
-
-class QoSSpecs(base.Resource):
- """QoS specs entity represents quality-of-service parameters/requirements.
-
- A QoS specs is a set of parameters or requirements for quality-of-service
- purpose, which can be associated with volume types (for now). In future,
- QoS specs may be extended to be associated other entities, such as single
- volume.
- """
- def __repr__(self):
- return "<QoSSpecs: %s>" % self.name
-
- def delete(self):
- return self.manager.delete(self)
-
-
-class QoSSpecsManager(base.ManagerWithFind):
- """
- Manage :class:`QoSSpecs` resources.
- """
- resource_class = QoSSpecs
-
- def list(self, search_opts=None):
- """Get a list of all qos specs.
-
- :rtype: list of :class:`QoSSpecs`.
- """
- return self._list("/qos-specs", "qos_specs")
-
- def get(self, qos_specs):
- """Get a specific qos specs.
-
- :param qos_specs: The ID of the :class:`QoSSpecs` to get.
- :rtype: :class:`QoSSpecs`
- """
- return self._get("/qos-specs/%s" % base.getid(qos_specs), "qos_specs")
-
- def delete(self, qos_specs, force=False):
- """Delete a specific qos specs.
-
- :param qos_specs: The ID of the :class:`QoSSpecs` to be removed.
- :param force: Flag that indicates whether to delete target qos specs
- if it was in-use.
- """
- return self._delete("/qos-specs/%s?force=%s" %
- (base.getid(qos_specs), force))
-
- def create(self, name, specs):
- """Create a qos specs.
-
- :param name: Descriptive name of the qos specs, must be unique
- :param specs: A dict of key/value pairs to be set
- :rtype: :class:`QoSSpecs`
- """
-
- body = {
- "qos_specs": {
- "name": name,
- }
- }
-
- body["qos_specs"].update(specs)
- return self._create("/qos-specs", body, "qos_specs")
-
- def set_keys(self, qos_specs, specs):
- """Add/Update keys in qos specs.
-
- :param qos_specs: The ID of qos specs
- :param specs: A dict of key/value pairs to be set
- :rtype: :class:`QoSSpecs`
- """
-
- body = {
- "qos_specs": {}
- }
-
- body["qos_specs"].update(specs)
- return self._update("/qos-specs/%s" % qos_specs, body)
-
- def unset_keys(self, qos_specs, specs):
- """Remove keys from a qos specs.
-
- :param qos_specs: The ID of qos specs
- :param specs: A list of key to be unset
- :rtype: :class:`QoSSpecs`
- """
-
- body = {'keys': specs}
-
- return self._update("/qos-specs/%s/delete_keys" % qos_specs,
- body)
-
- def get_associations(self, qos_specs):
- """Get associated entities of a qos specs.
-
- :param qos_specs: The id of the :class: `QoSSpecs`
- :return: a list of entities that associated with specific qos specs.
- """
- return self._list("/qos-specs/%s/associations" % base.getid(qos_specs),
- "qos_associations")
-
- def associate(self, qos_specs, vol_type_id):
- """Associate a volume type with specific qos specs.
-
- :param qos_specs: The qos specs to be associated with
- :param vol_type_id: The volume type id to be associated with
- """
- resp, body = self.api.client.get(
- "/qos-specs/%s/associate?vol_type_id=%s" %
- (base.getid(qos_specs), vol_type_id))
- return common_base.TupleWithMeta((resp, body), resp)
-
- def disassociate(self, qos_specs, vol_type_id):
- """Disassociate qos specs from volume type.
-
- :param qos_specs: The qos specs to be associated with
- :param vol_type_id: The volume type id to be associated with
- """
- resp, body = self.api.client.get(
- "/qos-specs/%s/disassociate?vol_type_id=%s" %
- (base.getid(qos_specs), vol_type_id))
- return common_base.TupleWithMeta((resp, body), resp)
-
- def disassociate_all(self, qos_specs):
- """Disassociate all entities from specific qos specs.
-
- :param qos_specs: The qos specs to be associated with
- """
- resp, body = self.api.client.get(
- "/qos-specs/%s/disassociate_all" %
- base.getid(qos_specs))
- return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v2/quota_classes.py b/cinderclient/v2/quota_classes.py
deleted file mode 100644
index 1958fa1..0000000
--- a/cinderclient/v2/quota_classes.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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 cinderclient import base
-
-
-class QuotaClassSet(base.Resource):
-
- @property
- def id(self):
- """Needed by base.Resource to self-refresh and be indexed."""
- return self.class_name
-
- def update(self, *args, **kwargs):
- return self.manager.update(self.class_name, *args, **kwargs)
-
-
-class QuotaClassSetManager(base.Manager):
- resource_class = QuotaClassSet
-
- def get(self, class_name):
- return self._get("/os-quota-class-sets/%s" % (class_name),
- "quota_class_set")
-
- def update(self, class_name, **updates):
- quota_class_set = {}
-
- for update in updates:
- quota_class_set[update] = updates[update]
-
- result = self._update('/os-quota-class-sets/%s' % (class_name),
- {'quota_class_set': quota_class_set})
- return self.resource_class(self,
- result['quota_class_set'], loaded=True,
- resp=result.request_ids)
diff --git a/cinderclient/v2/quotas.py b/cinderclient/v2/quotas.py
deleted file mode 100644
index bebf32a..0000000
--- a/cinderclient/v2/quotas.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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 cinderclient import base
-
-
-class QuotaSet(base.Resource):
-
- @property
- def id(self):
- """Needed by base.Resource to self-refresh and be indexed."""
- return self.tenant_id
-
- def update(self, *args, **kwargs):
- return self.manager.update(self.tenant_id, *args, **kwargs)
-
-
-class QuotaSetManager(base.Manager):
- resource_class = QuotaSet
-
- def get(self, tenant_id, usage=False):
- if hasattr(tenant_id, 'tenant_id'):
- tenant_id = tenant_id.tenant_id
- return self._get("/os-quota-sets/%s?usage=%s" % (tenant_id, usage),
- "quota_set")
-
- def update(self, tenant_id, **updates):
- body = {'quota_set': {'tenant_id': tenant_id}}
-
- for update in updates:
- body['quota_set'][update] = updates[update]
-
- result = self._update('/os-quota-sets/%s' % (tenant_id), body)
- return self.resource_class(self, result['quota_set'], loaded=True,
- resp=result.request_ids)
-
- def defaults(self, tenant_id):
- return self._get('/os-quota-sets/%s/defaults' % tenant_id,
- 'quota_set')
-
- def delete(self, tenant_id):
- if hasattr(tenant_id, 'tenant_id'):
- tenant_id = tenant_id.tenant_id
- return self._delete("/os-quota-sets/%s" % tenant_id)
diff --git a/cinderclient/v2/services.py b/cinderclient/v2/services.py
deleted file mode 100644
index 68ea1bc..0000000
--- a/cinderclient/v2/services.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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.
-
-"""
-service interface
-"""
-
-from cinderclient import base
-
-
-class Service(base.Resource):
-
- def __repr__(self):
- return "<Service: binary=%s host=%s>" % (self.binary, self.host)
-
-
-class ServiceManager(base.ManagerWithFind):
- resource_class = Service
-
- def list(self, host=None, binary=None):
- """
- Describes service list for host.
-
- :param host: destination host name.
- :param binary: service binary.
- """
- url = "/os-services"
- filters = []
- if host:
- filters.append("host=%s" % host)
- if binary:
- filters.append("binary=%s" % binary)
- if filters:
- url = "%s?%s" % (url, "&".join(filters))
- return self._list(url, "services")
-
- def enable(self, host, binary):
- """Enable the service specified by hostname and binary."""
- body = {"host": host, "binary": binary}
- result = self._update("/os-services/enable", body)
- return self.resource_class(self, result, resp=result.request_ids)
-
- def disable(self, host, binary):
- """Disable the service specified by hostname and binary."""
- body = {"host": host, "binary": binary}
- result = self._update("/os-services/disable", body)
- return self.resource_class(self, result, resp=result.request_ids)
-
- def disable_log_reason(self, host, binary, reason):
- """Disable the service with reason."""
- body = {"host": host, "binary": binary, "disabled_reason": reason}
- result = self._update("/os-services/disable-log-reason", body)
- return self.resource_class(self, result, resp=result.request_ids)
-
- def freeze_host(self, host):
- """Freeze the service specified by hostname."""
- body = {"host": host}
- return self._update("/os-services/freeze", body)
-
- def thaw_host(self, host):
- """Thaw the service specified by hostname."""
- body = {"host": host}
- return self._update("/os-services/thaw", body)
-
- def failover_host(self, host, backend_id):
- """Failover a replicated backend by hostname."""
- body = {"host": host, "backend_id": backend_id}
- return self._update("/os-services/failover_host", body)
diff --git a/cinderclient/v2/volume_backups.py b/cinderclient/v2/volume_backups.py
deleted file mode 100644
index bcf3e01..0000000
--- a/cinderclient/v2/volume_backups.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""
-Volume Backups interface (v2 extension).
-"""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-
-
-class VolumeBackup(base.Resource):
- """A volume backup is a block level backup of a volume."""
-
- def __repr__(self):
- return "<VolumeBackup: %s>" % self.id
-
- def delete(self, force=False):
- """Delete this volume backup."""
- return self.manager.delete(self, force)
-
- def reset_state(self, state):
- return self.manager.reset_state(self, state)
-
- def update(self, **kwargs):
- """Update the name or description for this backup."""
- return self.manager.update(self, **kwargs)
-
-
-class VolumeBackupManager(base.ManagerWithFind):
- """Manage :class:`VolumeBackup` resources."""
- resource_class = VolumeBackup
-
- def create(self, volume_id, container=None,
- name=None, description=None,
- incremental=False, force=False,
- snapshot_id=None):
- """Creates a volume backup.
-
- :param volume_id: The ID of the volume to backup.
- :param container: The name of the backup service container.
- :param name: The name of the backup.
- :param description: The description of the backup.
- :param incremental: Incremental backup.
- :param force: If True, allows an in-use volume to be backed up.
- :param snapshot_id: The ID of the snapshot to backup. This should
- be a snapshot of the src volume, when specified,
- the new backup will be based on the snapshot.
- :rtype: :class:`VolumeBackup`
- """
- body = {'backup': {'volume_id': volume_id,
- 'container': container,
- 'name': name,
- 'description': description,
- 'incremental': incremental,
- 'force': force,
- 'snapshot_id': snapshot_id, }}
- return self._create('/backups', body, 'backup')
-
- def get(self, backup_id):
- """Show volume backup details.
-
- :param backup_id: The ID of the backup to display.
- :rtype: :class:`VolumeBackup`
- """
- return self._get("/backups/%s" % backup_id, "backup")
-
- def list(self, detailed=True, search_opts=None, marker=None, limit=None,
- sort=None):
- """Get a list of all volume backups.
-
- :rtype: list of :class:`VolumeBackup`
- """
- resource_type = "backups"
- url = self._build_list_url(resource_type, detailed=detailed,
- search_opts=search_opts, marker=marker,
- limit=limit, sort=sort)
- return self._list(url, resource_type, limit=limit)
-
- def delete(self, backup, force=False):
- """Delete a volume backup.
-
- :param backup: The :class:`VolumeBackup` to delete.
- :param force: Allow delete in state other than error or available.
- """
- if force:
- return self._action('os-force_delete', backup)
- else:
- return self._delete("/backups/%s" % base.getid(backup))
-
- def reset_state(self, backup, state):
- """Update the specified volume backup with the provided state."""
- return self._action('os-reset_status', backup,
- {'status': state} if state else {})
-
- def _action(self, action, backup, info=None, **kwargs):
- """Perform a volume backup action."""
- body = {action: info}
- self.run_hooks('modify_body_for_action', body, **kwargs)
- url = '/backups/%s/action' % base.getid(backup)
- resp, body = self.api.client.post(url, body=body)
- return common_base.TupleWithMeta((resp, body), resp)
-
- def export_record(self, backup_id):
- """Export volume backup metadata record.
-
- :param backup_id: The ID of the backup to export.
- :rtype: A dictionary containing 'backup_url' and 'backup_service'.
- """
- resp, body = \
- self.api.client.get("/backups/%s/export_record" % backup_id)
- return common_base.DictWithMeta(body['backup-record'], resp)
-
- def import_record(self, backup_service, backup_url):
- """Import volume backup metadata record.
-
- :param backup_service: Backup service to use for importing the backup
- :param backup_url: Backup URL for importing the backup metadata
- :rtype: A dictionary containing volume backup metadata.
- """
- body = {'backup-record': {'backup_service': backup_service,
- 'backup_url': backup_url}}
- self.run_hooks('modify_body_for_update', body, 'backup-record')
- resp, body = self.api.client.post("/backups/import_record", body=body)
- return common_base.DictWithMeta(body['backup'], resp)
diff --git a/cinderclient/v2/volume_backups_restore.py b/cinderclient/v2/volume_backups_restore.py
deleted file mode 100644
index a76cb09..0000000
--- a/cinderclient/v2/volume_backups_restore.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""Volume Backups Restore interface (v2 extension).
-
-This is part of the Volume Backups interface.
-"""
-
-from cinderclient import base
-
-
-class VolumeBackupsRestore(base.Resource):
- """A Volume Backups Restore represents a restore operation."""
- def __repr__(self):
- return "<VolumeBackupsRestore: %s>" % self.volume_id
-
-
-class VolumeBackupRestoreManager(base.Manager):
- """Manage :class:`VolumeBackupsRestore` resources."""
- resource_class = VolumeBackupsRestore
-
- def restore(self, backup_id, volume_id=None, name=None):
- """Restore a backup to a volume.
-
- :param backup_id: The ID of the backup to restore.
- :param volume_id: The ID of the volume to restore the backup to.
- :param name : The name for new volume creation to restore.
- :rtype: :class:`Restore`
- """
- body = {'restore': {'volume_id': volume_id, 'name': name}}
- return self._create("/backups/%s/restore" % backup_id,
- body, "restore")
diff --git a/cinderclient/v2/volume_encryption_types.py b/cinderclient/v2/volume_encryption_types.py
deleted file mode 100644
index 9edacf9..0000000
--- a/cinderclient/v2/volume_encryption_types.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (c) 2013 The Johns Hopkins University/Applied Physics Laboratory
-# 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.
-
-"""
-Volume Encryption Type interface
-"""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-
-
-class VolumeEncryptionType(base.Resource):
- """
- A Volume Encryption Type is a collection of settings used to conduct
- encryption for a specific volume type.
- """
- def __repr__(self):
- return "<VolumeEncryptionType: %s>" % self.encryption_id
-
-
-class VolumeEncryptionTypeManager(base.ManagerWithFind):
- """
- Manage :class: `VolumeEncryptionType` resources.
- """
- resource_class = VolumeEncryptionType
-
- def list(self, search_opts=None):
- """
- List all volume encryption types.
-
- :param search_opts: Search options to filter out volume
- encryption types
- :return: a list of :class: VolumeEncryptionType instances
- """
- # Since the encryption type is a volume type extension, we cannot get
- # all encryption types without going through all volume types.
- volume_types = self.api.volume_types.list()
- encryption_types = []
- list_of_resp = []
- for volume_type in volume_types:
- encryption_type = self._get("/types/%s/encryption"
- % base.getid(volume_type))
- if hasattr(encryption_type, 'volume_type_id'):
- encryption_types.append(encryption_type)
-
- list_of_resp.extend(encryption_type.request_ids)
-
- return common_base.ListWithMeta(encryption_types, list_of_resp)
-
- def get(self, volume_type):
- """
- Get the volume encryption type for the specified volume type.
-
- :param volume_type: the volume type to query
- :return: an instance of :class: VolumeEncryptionType
- """
- return self._get("/types/%s/encryption" % base.getid(volume_type))
-
- def create(self, volume_type, specs):
- """
- Creates encryption type for a volume type. Default: admin only.
-
- :param volume_type: the volume type on which to add an encryption type
- :param specs: the encryption type specifications to add
- :return: an instance of :class: VolumeEncryptionType
- """
- body = {'encryption': specs}
- return self._create("/types/%s/encryption" % base.getid(volume_type),
- body, "encryption")
-
- def update(self, volume_type, specs):
- """
- Update the encryption type information for the specified volume type.
-
- :param volume_type: the volume type whose encryption type information
- must be updated
- :param specs: the encryption type specifications to update
- :return: an instance of :class: VolumeEncryptionType
- """
- body = {'encryption': specs}
- return self._update("/types/%s/encryption/provider" %
- base.getid(volume_type), body)
-
- def delete(self, volume_type):
- """
- Delete the encryption type information for the specified volume type.
-
- :param volume_type: the volume type whose encryption type information
- must be deleted
- """
- return self._delete("/types/%s/encryption/provider" %
- base.getid(volume_type))
diff --git a/cinderclient/v2/volume_snapshots.py b/cinderclient/v2/volume_snapshots.py
deleted file mode 100644
index a89c135..0000000
--- a/cinderclient/v2/volume_snapshots.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-# 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.
-
-"""Volume snapshot interface (v2 extension)."""
-
-from cinderclient import api_versions
-from cinderclient.v3 import volume_snapshots
-
-
-class Snapshot(volume_snapshots.Snapshot):
- def list_manageable(self, host, detailed=True, marker=None, limit=None,
- offset=None, sort=None):
- return self.manager.list_manageable(host, detailed=detailed,
- marker=marker, limit=limit,
- offset=offset, sort=sort)
-
-
-class SnapshotManager(volume_snapshots.SnapshotManager):
- resource_class = Snapshot
-
- @api_versions.wraps("2.0")
- def list_manageable(self, host, detailed=True, marker=None, limit=None,
- offset=None, sort=None):
- url = self._build_list_url("os-snapshot-manage", detailed=detailed,
- search_opts={'host': host}, marker=marker,
- limit=limit, offset=offset, sort=sort)
- return self._list(url, "manageable-snapshots")
diff --git a/cinderclient/v2/volume_transfers.py b/cinderclient/v2/volume_transfers.py
deleted file mode 100644
index 00508c0..0000000
--- a/cinderclient/v2/volume_transfers.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""
-Volume transfer interface (v2 extension).
-"""
-
-from cinderclient import base
-from cinderclient import utils
-
-
-class VolumeTransfer(base.Resource):
- """Transfer a volume from one tenant to another"""
-
- def __repr__(self):
- return "<VolumeTransfer: %s>" % self.id
-
- def delete(self):
- """Delete this volume transfer."""
- return self.manager.delete(self)
-
-
-class VolumeTransferManager(base.ManagerWithFind):
- """Manage :class:`VolumeTransfer` resources."""
- resource_class = VolumeTransfer
-
- def create(self, volume_id, name=None):
- """Creates a volume transfer.
-
- :param volume_id: The ID of the volume to transfer.
- :param name: The name of the transfer.
- :rtype: :class:`VolumeTransfer`
- """
- body = {'transfer': {'volume_id': volume_id,
- 'name': name}}
- return self._create('/os-volume-transfer', body, 'transfer')
-
- def accept(self, transfer_id, auth_key):
- """Accept a volume transfer.
-
- :param transfer_id: The ID of the transfer to accept.
- :param auth_key: The auth_key of the transfer.
- :rtype: :class:`VolumeTransfer`
- """
- body = {'accept': {'auth_key': auth_key}}
- return self._create('/os-volume-transfer/%s/accept' % transfer_id,
- body, 'transfer')
-
- def get(self, transfer_id):
- """Show details of a volume transfer.
-
- :param transfer_id: The ID of the volume transfer to display.
- :rtype: :class:`VolumeTransfer`
- """
- return self._get("/os-volume-transfer/%s" % transfer_id, "transfer")
-
- def list(self, detailed=True, search_opts=None):
- """Get a list of all volume transfer.
-
- :rtype: list of :class:`VolumeTransfer`
- """
- query_string = utils.build_query_param(search_opts)
-
- detail = ""
- if detailed:
- detail = "/detail"
-
- return self._list("/os-volume-transfer%s%s" % (detail, query_string),
- "transfers")
-
- def delete(self, transfer_id):
- """Delete a volume transfer.
-
- :param transfer_id: The :class:`VolumeTransfer` to delete.
- """
- return self._delete("/os-volume-transfer/%s" % base.getid(transfer_id))
diff --git a/cinderclient/v2/volume_type_access.py b/cinderclient/v2/volume_type_access.py
deleted file mode 100644
index bdd2e70..0000000
--- a/cinderclient/v2/volume_type_access.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-#
-# 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.
-
-"""Volume type access interface."""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-
-
-class VolumeTypeAccess(base.Resource):
- def __repr__(self):
- return "<VolumeTypeAccess: %s>" % self.project_id
-
-
-class VolumeTypeAccessManager(base.ManagerWithFind):
- """
- Manage :class:`VolumeTypeAccess` resources.
- """
- resource_class = VolumeTypeAccess
-
- def list(self, volume_type):
- return self._list(
- '/types/%s/os-volume-type-access' % base.getid(volume_type),
- 'volume_type_access')
-
- def add_project_access(self, volume_type, project):
- """Add a project to the given volume type access list."""
- info = {'project': project}
- return self._action('addProjectAccess', volume_type, info)
-
- def remove_project_access(self, volume_type, project):
- """Remove a project from the given volume type access list."""
- info = {'project': project}
- return self._action('removeProjectAccess', volume_type, info)
-
- def _action(self, action, volume_type, info, **kwargs):
- """Perform a volume type action."""
- body = {action: info}
- self.run_hooks('modify_body_for_action', body, **kwargs)
- url = '/types/%s/action' % base.getid(volume_type)
- resp, body = self.api.client.post(url, body=body)
- return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v2/volume_types.py b/cinderclient/v2/volume_types.py
deleted file mode 100644
index 546d776..0000000
--- a/cinderclient/v2/volume_types.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# Copyright (c) 2013 OpenStack Foundation
-#
-# 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.
-
-"""Volume Type interface."""
-
-from cinderclient.apiclient import base as common_base
-from cinderclient import base
-
-
-class VolumeType(base.Resource):
- """A Volume Type is the type of volume to be created."""
- def __repr__(self):
- return "<VolumeType: %s>" % self.name
-
- @property
- def is_public(self):
- """
- Provide a user-friendly accessor to os-volume-type-access:is_public
- """
- return self._info.get("os-volume-type-access:is_public",
- self._info.get("is_public", 'N/A'))
-
- def get_keys(self):
- """Get extra specs from a volume type.
-
- :param vol_type: The :class:`VolumeType` to get extra specs from
- """
- _resp, body = self.manager.api.client.get(
- "/types/%s/extra_specs" %
- base.getid(self))
- return body["extra_specs"]
-
- def set_keys(self, metadata):
- """Set extra specs on a volume type.
-
- :param type : The :class:`VolumeType` to set extra spec on
- :param metadata: A dict of key/value pairs to be set
- """
- body = {'extra_specs': metadata}
- return self.manager._create(
- "/types/%s/extra_specs" % base.getid(self),
- body,
- "extra_specs",
- return_raw=True)
-
- def unset_keys(self, keys):
- """Unset extra specs on a volue type.
-
- :param type_id: The :class:`VolumeType` to unset extra spec on
- :param keys: A list of keys to be unset
- """
-
- # NOTE(jdg): This wasn't actually doing all of the keys before
- # the return in the loop resulted in only ONE key being unset,
- # since on success the return was ListWithMeta class, we'll only
- # interrupt the loop and if an exception is raised.
- response_list = []
- for k in keys:
- resp, body = self.manager._delete(
- "/types/%s/extra_specs/%s" % (
- base.getid(self), k))
- response_list.append(resp)
-
- return common_base.ListWithMeta([], response_list)
-
-
-class VolumeTypeManager(base.ManagerWithFind):
- """Manage :class:`VolumeType` resources."""
- resource_class = VolumeType
-
- def list(self, search_opts=None, is_public=None):
- """Lists all volume types.
-
- :rtype: list of :class:`VolumeType`.
- """
- query_string = ''
- if not is_public:
- query_string = '?is_public=%s' % is_public
- return self._list("/types%s" % (query_string), "volume_types")
-
- def get(self, volume_type):
- """Get a specific volume type.
-
- :param volume_type: The ID of the :class:`VolumeType` to get.
- :rtype: :class:`VolumeType`
- """
- return self._get("/types/%s" % base.getid(volume_type), "volume_type")
-
- def default(self):
- """Get the default volume type.
-
- :rtype: :class:`VolumeType`
- """
- return self._get("/types/default", "volume_type")
-
- def delete(self, volume_type):
- """Deletes a specific volume_type.
-
- :param volume_type: The name or ID of the :class:`VolumeType` to get.
- """
- return self._delete("/types/%s" % base.getid(volume_type))
-
- def create(self, name, description=None, is_public=True):
- """Creates a volume type.
-
- :param name: Descriptive name of the volume type
- :param description: Description of the volume type
- :param is_public: Volume type visibility
- :rtype: :class:`VolumeType`
- """
-
- body = {
- "volume_type": {
- "name": name,
- "description": description,
- "os-volume-type-access:is_public": is_public,
- }
- }
-
- return self._create("/types", body, "volume_type")
-
- def update(self, volume_type, name=None, description=None, is_public=None):
- """Update the name and/or description for a volume type.
-
- :param volume_type: The ID of the :class:`VolumeType` to update.
- :param name: Descriptive name of the volume type.
- :param description: Description of the volume type.
- :rtype: :class:`VolumeType`
- """
-
- body = {
- "volume_type": {
- "name": name,
- "description": description
- }
- }
- if is_public is not None:
- body["volume_type"]["is_public"] = is_public
-
- return self._update("/types/%s" % base.getid(volume_type),
- body, response_key="volume_type")
diff --git a/cinderclient/v3/capabilities.py b/cinderclient/v3/capabilities.py
index 76a3b4e..c837a40 100644
--- a/cinderclient/v3/capabilities.py
+++ b/cinderclient/v3/capabilities.py
@@ -16,4 +16,24 @@
"""Capabilities interface (v3 extension)"""
-from cinderclient.v2.capabilities import * # noqa
+from cinderclient import base
+
+
+class Capabilities(base.Resource):
+ NAME_ATTR = 'name'
+
+ def __repr__(self):
+ return "<Capabilities: %s>" % self._info.get('namespace')
+
+
+class CapabilitiesManager(base.Manager):
+ """Manage :class:`Capabilities` resources."""
+ resource_class = Capabilities
+
+ def get(self, host):
+ """Show backend volume stats and properties.
+
+ :param host: Specified backend to obtain volume stats and properties.
+ :rtype: :class:`Capabilities`
+ """
+ return self._get('/capabilities/%s' % host, None)
diff --git a/cinderclient/v3/cgsnapshots.py b/cinderclient/v3/cgsnapshots.py
index 0ed0cdc..1f5abc6 100644
--- a/cinderclient/v3/cgsnapshots.py
+++ b/cinderclient/v3/cgsnapshots.py
@@ -15,4 +15,98 @@
"""cgsnapshot interface (v3 extension)."""
-from cinderclient.v2.cgsnapshots import * # noqa
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+from cinderclient import utils
+
+
+class Cgsnapshot(base.Resource):
+ """A cgsnapshot is snapshot of a consistency group."""
+ def __repr__(self):
+ return "<cgsnapshot: %s>" % self.id
+
+ def delete(self):
+ """Delete this cgsnapshot."""
+ return self.manager.delete(self)
+
+ def update(self, **kwargs):
+ """Update the name or description for this cgsnapshot."""
+ return self.manager.update(self, **kwargs)
+
+
+class CgsnapshotManager(base.ManagerWithFind):
+ """Manage :class:`Cgsnapshot` resources."""
+ resource_class = Cgsnapshot
+
+ def create(self, consistencygroup_id, name=None, description=None,
+ user_id=None,
+ project_id=None):
+ """Creates a cgsnapshot.
+
+ :param consistencygroup: Name or uuid of a consistency group
+ :param name: Name of the cgsnapshot
+ :param description: Description of the cgsnapshot
+ :param user_id: User id derived from context
+ :param project_id: Project id derived from context
+ :rtype: :class:`Cgsnapshot`
+ """
+
+ body = {'cgsnapshot': {'consistencygroup_id': consistencygroup_id,
+ 'name': name,
+ 'description': description,
+ 'user_id': user_id,
+ 'project_id': project_id,
+ 'status': "creating",
+ }}
+
+ return self._create('/cgsnapshots', body, 'cgsnapshot')
+
+ def get(self, cgsnapshot_id):
+ """Get a cgsnapshot.
+
+ :param cgsnapshot_id: The ID of the cgsnapshot to get.
+ :rtype: :class:`Cgsnapshot`
+ """
+ return self._get("/cgsnapshots/%s" % cgsnapshot_id, "cgsnapshot")
+
+ def list(self, detailed=True, search_opts=None):
+ """Lists all cgsnapshots.
+
+ :rtype: list of :class:`Cgsnapshot`
+ """
+ query_string = utils.build_query_param(search_opts)
+
+ detail = ""
+ if detailed:
+ detail = "/detail"
+
+ return self._list("/cgsnapshots%s%s" % (detail, query_string),
+ "cgsnapshots")
+
+ def delete(self, cgsnapshot):
+ """Delete a cgsnapshot.
+
+ :param cgsnapshot: The :class:`Cgsnapshot` to delete.
+ """
+ return self._delete("/cgsnapshots/%s" % base.getid(cgsnapshot))
+
+ def update(self, cgsnapshot, **kwargs):
+ """Update the name or description for a cgsnapshot.
+
+ :param cgsnapshot: The :class:`Cgsnapshot` to update.
+ """
+ if not kwargs:
+ return
+
+ body = {"cgsnapshot": kwargs}
+
+ return self._update("/cgsnapshots/%s" % base.getid(cgsnapshot), body)
+
+ def _action(self, action, cgsnapshot, info=None, **kwargs):
+ """Perform a cgsnapshot "action."
+ """
+ body = {action: info}
+ self.run_hooks('modify_body_for_action', body, **kwargs)
+ url = '/cgsnapshots/%s/action' % base.getid(cgsnapshot)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v3/consistencygroups.py b/cinderclient/v3/consistencygroups.py
index a29fd83..13bc2ee 100644
--- a/cinderclient/v3/consistencygroups.py
+++ b/cinderclient/v3/consistencygroups.py
@@ -15,4 +15,135 @@
"""Consistencygroup interface (v3 extension)."""
-from cinderclient.v2.consistencygroups import * # noqa
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+from cinderclient import utils
+
+
+class Consistencygroup(base.Resource):
+ """A Consistencygroup of volumes."""
+ def __repr__(self):
+ return "<Consistencygroup: %s>" % self.id
+
+ def delete(self, force='False'):
+ """Delete this consistency group."""
+ return self.manager.delete(self, force)
+
+ def update(self, **kwargs):
+ """Update the name or description for this consistency group."""
+ return self.manager.update(self, **kwargs)
+
+
+class ConsistencygroupManager(base.ManagerWithFind):
+ """Manage :class:`Consistencygroup` resources."""
+ resource_class = Consistencygroup
+
+ def create(self, volume_types, name=None,
+ description=None, user_id=None,
+ project_id=None, availability_zone=None):
+ """Creates a consistency group.
+
+ :param name: Name of the ConsistencyGroup
+ :param description: Description of the ConsistencyGroup
+ :param volume_types: Types of volume
+ :param user_id: User id derived from context
+ :param project_id: Project id derived from context
+ :param availability_zone: Availability Zone to use
+ :rtype: :class:`Consistencygroup`
+ """
+
+ body = {'consistencygroup': {'name': name,
+ 'description': description,
+ 'volume_types': volume_types,
+ 'user_id': user_id,
+ 'project_id': project_id,
+ 'availability_zone': availability_zone,
+ 'status': "creating",
+ }}
+
+ return self._create('/consistencygroups', body, 'consistencygroup')
+
+ def create_from_src(self, cgsnapshot_id, source_cgid, name=None,
+ description=None, user_id=None,
+ project_id=None):
+ """Creates a consistency group from a cgsnapshot or a source CG.
+
+ :param cgsnapshot_id: UUID of a CGSnapshot
+ :param source_cgid: UUID of a source CG
+ :param name: Name of the ConsistencyGroup
+ :param description: Description of the ConsistencyGroup
+ :param user_id: User id derived from context
+ :param project_id: Project id derived from context
+ :rtype: A dictionary containing Consistencygroup metadata
+ """
+ body = {'consistencygroup-from-src': {'name': name,
+ 'description': description,
+ 'cgsnapshot_id': cgsnapshot_id,
+ 'source_cgid': source_cgid,
+ 'user_id': user_id,
+ 'project_id': project_id,
+ 'status': "creating",
+ }}
+
+ self.run_hooks('modify_body_for_update', body,
+ 'consistencygroup-from-src')
+ resp, body = self.api.client.post(
+ "/consistencygroups/create_from_src", body=body)
+ return common_base.DictWithMeta(body['consistencygroup'], resp)
+
+ def get(self, group_id):
+ """Get a consistency group.
+
+ :param group_id: The ID of the consistency group to get.
+ :rtype: :class:`Consistencygroup`
+ """
+ return self._get("/consistencygroups/%s" % group_id,
+ "consistencygroup")
+
+ def list(self, detailed=True, search_opts=None):
+ """Lists all consistency groups.
+
+ :rtype: list of :class:`Consistencygroup`
+ """
+
+ query_string = utils.build_query_param(search_opts)
+
+ detail = ""
+ if detailed:
+ detail = "/detail"
+
+ return self._list("/consistencygroups%s%s" % (detail, query_string),
+ "consistencygroups")
+
+ def delete(self, consistencygroup, force=False):
+ """Delete a consistency group.
+
+ :param Consistencygroup: The :class:`Consistencygroup` to delete.
+ """
+ body = {'consistencygroup': {'force': force}}
+ self.run_hooks('modify_body_for_action', body, 'consistencygroup')
+ url = '/consistencygroups/%s/delete' % base.getid(consistencygroup)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def update(self, consistencygroup, **kwargs):
+ """Update the name or description for a consistency group.
+
+ :param Consistencygroup: The :class:`Consistencygroup` to update.
+ """
+ if not kwargs:
+ return
+
+ body = {"consistencygroup": kwargs}
+
+ return self._update("/consistencygroups/%s" %
+ base.getid(consistencygroup), body)
+
+ def _action(self, action, consistencygroup, info=None, **kwargs):
+ """Perform a consistency group "action."
+ """
+ body = {action: info}
+ self.run_hooks('modify_body_for_action', body, **kwargs)
+ url = '/consistencygroups/%s/action' % base.getid(consistencygroup)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v3/contrib/list_extensions.py b/cinderclient/v3/contrib/list_extensions.py
index 0b5e845..937d34b 100644
--- a/cinderclient/v3/contrib/list_extensions.py
+++ b/cinderclient/v3/contrib/list_extensions.py
@@ -13,4 +13,32 @@
# License for the specific language governing permissions and limitations
# under the License.
-from cinderclient.v2.contrib.list_extensions import * # noqa
+from cinderclient import base
+from cinderclient import utils
+
+
+class ListExtResource(base.Resource):
+ @property
+ def summary(self):
+ descr = self.description.strip()
+ if not descr:
+ return '??'
+ lines = descr.split("\n")
+ if len(lines) == 1:
+ return lines[0]
+ else:
+ return lines[0] + "..."
+
+
+class ListExtManager(base.Manager):
+ resource_class = ListExtResource
+
+ def show_all(self):
+ return self._list("/extensions", 'extensions')
+
+
+def do_list_extensions(client, _args):
+ """Lists all available os-api extensions."""
+ extensions = client.list_extensions.show_all()
+ fields = ["Name", "Summary", "Alias", "Updated"]
+ utils.print_list(extensions, fields)
diff --git a/cinderclient/v3/limits.py b/cinderclient/v3/limits.py
index 29d1dca..69f053f 100644
--- a/cinderclient/v3/limits.py
+++ b/cinderclient/v3/limits.py
@@ -13,4 +13,86 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from cinderclient.v2.limits import * # noqa
+from cinderclient import base
+from cinderclient import utils
+
+
+class Limits(base.Resource):
+ """A collection of RateLimit and AbsoluteLimit objects."""
+
+ def __repr__(self):
+ return "<Limits>"
+
+ @property
+ def absolute(self):
+ for (name, value) in list(self._info['absolute'].items()):
+ yield AbsoluteLimit(name, value)
+
+ @property
+ def rate(self):
+ for group in self._info['rate']:
+ uri = group['uri']
+ regex = group['regex']
+ for rate in group['limit']:
+ yield RateLimit(rate['verb'], uri, regex, rate['value'],
+ rate['remaining'], rate['unit'],
+ rate['next-available'])
+
+
+class RateLimit(object):
+ """Data model that represents a flattened view of a single rate limit."""
+
+ def __init__(self, verb, uri, regex, value, remain,
+ unit, next_available):
+ self.verb = verb
+ self.uri = uri
+ self.regex = regex
+ self.value = value
+ self.remain = remain
+ self.unit = unit
+ self.next_available = next_available
+
+ def __eq__(self, other):
+ return self.uri == other.uri \
+ and self.regex == other.regex \
+ and self.value == other.value \
+ and self.verb == other.verb \
+ and self.remain == other.remain \
+ and self.unit == other.unit \
+ and self.next_available == other.next_available
+
+ def __repr__(self):
+ return "<RateLimit: method=%s uri=%s>" % (self.verb, self.uri)
+
+
+class AbsoluteLimit(object):
+ """Data model that represents a single absolute limit."""
+
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
+
+ def __eq__(self, other):
+ return self.value == other.value and self.name == other.name
+
+ def __repr__(self):
+ return "<AbsoluteLimit: name=%s>" % (self.name)
+
+
+class LimitsManager(base.Manager):
+ """Manager object used to interact with limits resource."""
+
+ resource_class = Limits
+
+ def get(self, tenant_id=None):
+ """Get a specific extension.
+
+ :rtype: :class:`Limits`
+ """
+ opts = {}
+ if tenant_id:
+ opts['tenant_id'] = tenant_id
+
+ query_string = utils.build_query_param(opts)
+
+ return self._get("/limits%s" % query_string, "limits")
diff --git a/cinderclient/v3/pools.py b/cinderclient/v3/pools.py
index f4ab422..5303f84 100644
--- a/cinderclient/v3/pools.py
+++ b/cinderclient/v3/pools.py
@@ -15,4 +15,46 @@
"""Pools interface (v3 extension)"""
-from cinderclient.v2.pools import * # noqa
+from cinderclient import base
+
+
+class Pool(base.Resource):
+ NAME_ATTR = 'name'
+
+ def __repr__(self):
+ return "<Pool: %s>" % self.name
+
+
+class PoolManager(base.Manager):
+ """Manage :class:`Pool` resources."""
+ resource_class = Pool
+
+ def list(self, detailed=False):
+ """Lists all
+
+ :rtype: list of :class:`Pool`
+ """
+ if detailed is True:
+ pools = self._list("/scheduler-stats/get_pools?detail=True",
+ "pools")
+ # Other than the name, all of the pool data is buried below in
+ # a 'capabilities' dictionary. In order to be consistent with the
+ # get-pools command line, these elements are moved up a level to
+ # be attributes of the pool itself.
+ for pool in pools:
+ if hasattr(pool, 'capabilities'):
+ for k, v in pool.capabilities.items():
+ setattr(pool, k, v)
+
+ # Remove the capabilities dictionary since all of its
+ # elements have been copied up to the containing pool
+ del pool.capabilities
+ return pools
+ else:
+ pools = self._list("/scheduler-stats/get_pools", "pools")
+
+ # avoid cluttering the basic pool list with capabilities dict
+ for pool in pools:
+ if hasattr(pool, 'capabilities'):
+ del pool.capabilities
+ return pools
diff --git a/cinderclient/v3/qos_specs.py b/cinderclient/v3/qos_specs.py
index f70b569..9723164 100644
--- a/cinderclient/v3/qos_specs.py
+++ b/cinderclient/v3/qos_specs.py
@@ -19,4 +19,138 @@
QoS Specs interface.
"""
-from cinderclient.v2.qos_specs import * # noqa
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+
+
+class QoSSpecs(base.Resource):
+ """QoS specs entity represents quality-of-service parameters/requirements.
+
+ A QoS specs is a set of parameters or requirements for quality-of-service
+ purpose, which can be associated with volume types (for now). In future,
+ QoS specs may be extended to be associated other entities, such as single
+ volume.
+ """
+ def __repr__(self):
+ return "<QoSSpecs: %s>" % self.name
+
+ def delete(self):
+ return self.manager.delete(self)
+
+
+class QoSSpecsManager(base.ManagerWithFind):
+ """
+ Manage :class:`QoSSpecs` resources.
+ """
+ resource_class = QoSSpecs
+
+ def list(self, search_opts=None):
+ """Get a list of all qos specs.
+
+ :rtype: list of :class:`QoSSpecs`.
+ """
+ return self._list("/qos-specs", "qos_specs")
+
+ def get(self, qos_specs):
+ """Get a specific qos specs.
+
+ :param qos_specs: The ID of the :class:`QoSSpecs` to get.
+ :rtype: :class:`QoSSpecs`
+ """
+ return self._get("/qos-specs/%s" % base.getid(qos_specs), "qos_specs")
+
+ def delete(self, qos_specs, force=False):
+ """Delete a specific qos specs.
+
+ :param qos_specs: The ID of the :class:`QoSSpecs` to be removed.
+ :param force: Flag that indicates whether to delete target qos specs
+ if it was in-use.
+ """
+ return self._delete("/qos-specs/%s?force=%s" %
+ (base.getid(qos_specs), force))
+
+ def create(self, name, specs):
+ """Create a qos specs.
+
+ :param name: Descriptive name of the qos specs, must be unique
+ :param specs: A dict of key/value pairs to be set
+ :rtype: :class:`QoSSpecs`
+ """
+
+ body = {
+ "qos_specs": {
+ "name": name,
+ }
+ }
+
+ body["qos_specs"].update(specs)
+ return self._create("/qos-specs", body, "qos_specs")
+
+ def set_keys(self, qos_specs, specs):
+ """Add/Update keys in qos specs.
+
+ :param qos_specs: The ID of qos specs
+ :param specs: A dict of key/value pairs to be set
+ :rtype: :class:`QoSSpecs`
+ """
+
+ body = {
+ "qos_specs": {}
+ }
+
+ body["qos_specs"].update(specs)
+ return self._update("/qos-specs/%s" % qos_specs, body)
+
+ def unset_keys(self, qos_specs, specs):
+ """Remove keys from a qos specs.
+
+ :param qos_specs: The ID of qos specs
+ :param specs: A list of key to be unset
+ :rtype: :class:`QoSSpecs`
+ """
+
+ body = {'keys': specs}
+
+ return self._update("/qos-specs/%s/delete_keys" % qos_specs,
+ body)
+
+ def get_associations(self, qos_specs):
+ """Get associated entities of a qos specs.
+
+ :param qos_specs: The id of the :class: `QoSSpecs`
+ :return: a list of entities that associated with specific qos specs.
+ """
+ return self._list("/qos-specs/%s/associations" % base.getid(qos_specs),
+ "qos_associations")
+
+ def associate(self, qos_specs, vol_type_id):
+ """Associate a volume type with specific qos specs.
+
+ :param qos_specs: The qos specs to be associated with
+ :param vol_type_id: The volume type id to be associated with
+ """
+ resp, body = self.api.client.get(
+ "/qos-specs/%s/associate?vol_type_id=%s" %
+ (base.getid(qos_specs), vol_type_id))
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def disassociate(self, qos_specs, vol_type_id):
+ """Disassociate qos specs from volume type.
+
+ :param qos_specs: The qos specs to be associated with
+ :param vol_type_id: The volume type id to be associated with
+ """
+ resp, body = self.api.client.get(
+ "/qos-specs/%s/disassociate?vol_type_id=%s" %
+ (base.getid(qos_specs), vol_type_id))
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def disassociate_all(self, qos_specs):
+ """Disassociate all entities from specific qos specs.
+
+ :param qos_specs: The qos specs to be associated with
+ """
+ resp, body = self.api.client.get(
+ "/qos-specs/%s/disassociate_all" %
+ base.getid(qos_specs))
+ return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v3/quota_classes.py b/cinderclient/v3/quota_classes.py
index 6936212..1958fa1 100644
--- a/cinderclient/v3/quota_classes.py
+++ b/cinderclient/v3/quota_classes.py
@@ -13,4 +13,35 @@
# License for the specific language governing permissions and limitations
# under the License.
-from cinderclient.v2.quota_classes import * # noqa
+from cinderclient import base
+
+
+class QuotaClassSet(base.Resource):
+
+ @property
+ def id(self):
+ """Needed by base.Resource to self-refresh and be indexed."""
+ return self.class_name
+
+ def update(self, *args, **kwargs):
+ return self.manager.update(self.class_name, *args, **kwargs)
+
+
+class QuotaClassSetManager(base.Manager):
+ resource_class = QuotaClassSet
+
+ def get(self, class_name):
+ return self._get("/os-quota-class-sets/%s" % (class_name),
+ "quota_class_set")
+
+ def update(self, class_name, **updates):
+ quota_class_set = {}
+
+ for update in updates:
+ quota_class_set[update] = updates[update]
+
+ result = self._update('/os-quota-class-sets/%s' % (class_name),
+ {'quota_class_set': quota_class_set})
+ return self.resource_class(self,
+ result['quota_class_set'], loaded=True,
+ resp=result.request_ids)
diff --git a/cinderclient/v3/quotas.py b/cinderclient/v3/quotas.py
index 63dfba8..1295f60 100644
--- a/cinderclient/v3/quotas.py
+++ b/cinderclient/v3/quotas.py
@@ -13,10 +13,28 @@
# License for the specific language governing permissions and limitations
# under the License.
-from cinderclient.v2 import quotas
+from cinderclient import base
-class QuotaSetManager(quotas.QuotaSetManager):
+class QuotaSet(base.Resource):
+
+ @property
+ def id(self):
+ """Needed by base.Resource to self-refresh and be indexed."""
+ return self.tenant_id
+
+ def update(self, *args, **kwargs):
+ return self.manager.update(self.tenant_id, *args, **kwargs)
+
+
+class QuotaSetManager(base.Manager):
+ resource_class = QuotaSet
+
+ def get(self, tenant_id, usage=False):
+ if hasattr(tenant_id, 'tenant_id'):
+ tenant_id = tenant_id.tenant_id
+ return self._get("/os-quota-sets/%s?usage=%s" % (tenant_id, usage),
+ "quota_set")
def update(self, tenant_id, **updates):
skip_validation = updates.pop('skip_validation', True)
@@ -32,3 +50,12 @@ class QuotaSetManager(quotas.QuotaSetManager):
result = self._update(request_url, body)
return self.resource_class(self, result['quota_set'], loaded=True,
resp=result.request_ids)
+
+ def defaults(self, tenant_id):
+ return self._get('/os-quota-sets/%s/defaults' % tenant_id,
+ 'quota_set')
+
+ def delete(self, tenant_id):
+ if hasattr(tenant_id, 'tenant_id'):
+ tenant_id = tenant_id.tenant_id
+ return self._delete("/os-quota-sets/%s" % tenant_id)
diff --git a/cinderclient/v3/services.py b/cinderclient/v3/services.py
index 55d3ee4..b48691f 100644
--- a/cinderclient/v3/services.py
+++ b/cinderclient/v3/services.py
@@ -19,9 +19,12 @@ service interface
from cinderclient import api_versions
from cinderclient import base
-from cinderclient.v2 import services
-Service = services.Service
+
+class Service(base.Resource):
+
+ def __repr__(self):
+ return "<Service: binary=%s host=%s>" % (self.binary, self.host)
class LogLevel(base.Resource):
@@ -30,7 +33,61 @@ class LogLevel(base.Resource):
self.binary, self.host, self.prefix, self.level)
-class ServiceManager(services.ServiceManager):
+class ServiceManagerBase(base.ManagerWithFind):
+ resource_class = Service
+
+ def list(self, host=None, binary=None):
+ """
+ Describes service list for host.
+
+ :param host: destination host name.
+ :param binary: service binary.
+ """
+ url = "/os-services"
+ filters = []
+ if host:
+ filters.append("host=%s" % host)
+ if binary:
+ filters.append("binary=%s" % binary)
+ if filters:
+ url = "%s?%s" % (url, "&".join(filters))
+ return self._list(url, "services")
+
+ def enable(self, host, binary):
+ """Enable the service specified by hostname and binary."""
+ body = {"host": host, "binary": binary}
+ result = self._update("/os-services/enable", body)
+ return self.resource_class(self, result, resp=result.request_ids)
+
+ def disable(self, host, binary):
+ """Disable the service specified by hostname and binary."""
+ body = {"host": host, "binary": binary}
+ result = self._update("/os-services/disable", body)
+ return self.resource_class(self, result, resp=result.request_ids)
+
+ def disable_log_reason(self, host, binary, reason):
+ """Disable the service with reason."""
+ body = {"host": host, "binary": binary, "disabled_reason": reason}
+ result = self._update("/os-services/disable-log-reason", body)
+ return self.resource_class(self, result, resp=result.request_ids)
+
+ def freeze_host(self, host):
+ """Freeze the service specified by hostname."""
+ body = {"host": host}
+ return self._update("/os-services/freeze", body)
+
+ def thaw_host(self, host):
+ """Thaw the service specified by hostname."""
+ body = {"host": host}
+ return self._update("/os-services/thaw", body)
+
+ def failover_host(self, host, backend_id):
+ """Failover a replicated backend by hostname."""
+ body = {"host": host, "backend_id": backend_id}
+ return self._update("/os-services/failover_host", body)
+
+
+class ServiceManager(ServiceManagerBase):
@api_versions.wraps("3.0")
def server_api_version(self):
"""Returns the API Version supported by the server.
diff --git a/cinderclient/v3/shell_base.py b/cinderclient/v3/shell_base.py
index e3f8682..4dc6da9 100644
--- a/cinderclient/v3/shell_base.py
+++ b/cinderclient/v3/shell_base.py
@@ -25,7 +25,7 @@ from cinderclient import base
from cinderclient import exceptions
from cinderclient import shell_utils
from cinderclient import utils
-from cinderclient.v2 import availability_zones
+from cinderclient.v3 import availability_zones
def _translate_attachments(info):
diff --git a/cinderclient/v3/volume_backups.py b/cinderclient/v3/volume_backups.py
index 22d25a3..61069c8 100644
--- a/cinderclient/v3/volume_backups.py
+++ b/cinderclient/v3/volume_backups.py
@@ -18,14 +18,32 @@ Volume Backups interface (v3 extension).
"""
from cinderclient import api_versions
+from cinderclient.apiclient import base as common_base
from cinderclient import base
-from cinderclient.v2 import volume_backups
-VolumeBackup = volume_backups.VolumeBackup
+class VolumeBackup(base.Resource):
+ """A volume backup is a block level backup of a volume."""
+ def __repr__(self):
+ return "<VolumeBackup: %s>" % self.id
+
+ def delete(self, force=False):
+ """Delete this volume backup."""
+ return self.manager.delete(self, force)
+
+ def reset_state(self, state):
+ return self.manager.reset_state(self, state)
+
+ def update(self, **kwargs):
+ """Update the name or description for this backup."""
+ return self.manager.update(self, **kwargs)
+
+
+class VolumeBackupManager(base.ManagerWithFind):
+ """Manage :class:`VolumeBackup` resources."""
+ resource_class = VolumeBackup
-class VolumeBackupManager(volume_backups.VolumeBackupManager):
@api_versions.wraps("3.9")
def update(self, backup, **kwargs):
"""Update the name or description for a backup.
@@ -124,3 +142,70 @@ class VolumeBackupManager(volume_backups.VolumeBackupManager):
if availability_zone:
body['backup']['availability_zone'] = availability_zone
return self._create('/backups', body, 'backup')
+
+ def get(self, backup_id):
+ """Show volume backup details.
+
+ :param backup_id: The ID of the backup to display.
+ :rtype: :class:`VolumeBackup`
+ """
+ return self._get("/backups/%s" % backup_id, "backup")
+
+ def list(self, detailed=True, search_opts=None, marker=None, limit=None,
+ sort=None):
+ """Get a list of all volume backups.
+
+ :rtype: list of :class:`VolumeBackup`
+ """
+ resource_type = "backups"
+ url = self._build_list_url(resource_type, detailed=detailed,
+ search_opts=search_opts, marker=marker,
+ limit=limit, sort=sort)
+ return self._list(url, resource_type, limit=limit)
+
+ def delete(self, backup, force=False):
+ """Delete a volume backup.
+
+ :param backup: The :class:`VolumeBackup` to delete.
+ :param force: Allow delete in state other than error or available.
+ """
+ if force:
+ return self._action('os-force_delete', backup)
+ else:
+ return self._delete("/backups/%s" % base.getid(backup))
+
+ def reset_state(self, backup, state):
+ """Update the specified volume backup with the provided state."""
+ return self._action('os-reset_status', backup,
+ {'status': state} if state else {})
+
+ def _action(self, action, backup, info=None, **kwargs):
+ """Perform a volume backup action."""
+ body = {action: info}
+ self.run_hooks('modify_body_for_action', body, **kwargs)
+ url = '/backups/%s/action' % base.getid(backup)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def export_record(self, backup_id):
+ """Export volume backup metadata record.
+
+ :param backup_id: The ID of the backup to export.
+ :rtype: A dictionary containing 'backup_url' and 'backup_service'.
+ """
+ resp, body = \
+ self.api.client.get("/backups/%s/export_record" % backup_id)
+ return common_base.DictWithMeta(body['backup-record'], resp)
+
+ def import_record(self, backup_service, backup_url):
+ """Import volume backup metadata record.
+
+ :param backup_service: Backup service to use for importing the backup
+ :param backup_url: Backup URL for importing the backup metadata
+ :rtype: A dictionary containing volume backup metadata.
+ """
+ body = {'backup-record': {'backup_service': backup_service,
+ 'backup_url': backup_url}}
+ self.run_hooks('modify_body_for_update', body, 'backup-record')
+ resp, body = self.api.client.post("/backups/import_record", body=body)
+ return common_base.DictWithMeta(body['backup'], resp)
diff --git a/cinderclient/v3/volume_backups_restore.py b/cinderclient/v3/volume_backups_restore.py
index 7e38c00..8a35ed1 100644
--- a/cinderclient/v3/volume_backups_restore.py
+++ b/cinderclient/v3/volume_backups_restore.py
@@ -18,4 +18,27 @@
This is part of the Volume Backups interface.
"""
-from cinderclient.v2.volume_backups_restore import * # noqa
+from cinderclient import base
+
+
+class VolumeBackupsRestore(base.Resource):
+ """A Volume Backups Restore represents a restore operation."""
+ def __repr__(self):
+ return "<VolumeBackupsRestore: %s>" % self.volume_id
+
+
+class VolumeBackupRestoreManager(base.Manager):
+ """Manage :class:`VolumeBackupsRestore` resources."""
+ resource_class = VolumeBackupsRestore
+
+ def restore(self, backup_id, volume_id=None, name=None):
+ """Restore a backup to a volume.
+
+ :param backup_id: The ID of the backup to restore.
+ :param volume_id: The ID of the volume to restore the backup to.
+ :param name : The name for new volume creation to restore.
+ :rtype: :class:`Restore`
+ """
+ body = {'restore': {'volume_id': volume_id, 'name': name}}
+ return self._create("/backups/%s/restore" % backup_id,
+ body, "restore")
diff --git a/cinderclient/v3/volume_encryption_types.py b/cinderclient/v3/volume_encryption_types.py
index 5077097..531e4d2 100644
--- a/cinderclient/v3/volume_encryption_types.py
+++ b/cinderclient/v3/volume_encryption_types.py
@@ -18,4 +18,88 @@
Volume Encryption Type interface
"""
-from cinderclient.v2.volume_encryption_types import * # noqa
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+
+
+class VolumeEncryptionType(base.Resource):
+ """
+ A Volume Encryption Type is a collection of settings used to conduct
+ encryption for a specific volume type.
+ """
+ def __repr__(self):
+ return "<VolumeEncryptionType: %s>" % self.encryption_id
+
+
+class VolumeEncryptionTypeManager(base.ManagerWithFind):
+ """
+ Manage :class: `VolumeEncryptionType` resources.
+ """
+ resource_class = VolumeEncryptionType
+
+ def list(self, search_opts=None):
+ """
+ List all volume encryption types.
+
+ :param search_opts: Search options to filter out volume
+ encryption types
+ :return: a list of :class: VolumeEncryptionType instances
+ """
+ # Since the encryption type is a volume type extension, we cannot get
+ # all encryption types without going through all volume types.
+ volume_types = self.api.volume_types.list()
+ encryption_types = []
+ list_of_resp = []
+ for volume_type in volume_types:
+ encryption_type = self._get("/types/%s/encryption"
+ % base.getid(volume_type))
+ if hasattr(encryption_type, 'volume_type_id'):
+ encryption_types.append(encryption_type)
+
+ list_of_resp.extend(encryption_type.request_ids)
+
+ return common_base.ListWithMeta(encryption_types, list_of_resp)
+
+ def get(self, volume_type):
+ """
+ Get the volume encryption type for the specified volume type.
+
+ :param volume_type: the volume type to query
+ :return: an instance of :class: VolumeEncryptionType
+ """
+ return self._get("/types/%s/encryption" % base.getid(volume_type))
+
+ def create(self, volume_type, specs):
+ """
+ Creates encryption type for a volume type. Default: admin only.
+
+ :param volume_type: the volume type on which to add an encryption type
+ :param specs: the encryption type specifications to add
+ :return: an instance of :class: VolumeEncryptionType
+ """
+ body = {'encryption': specs}
+ return self._create("/types/%s/encryption" % base.getid(volume_type),
+ body, "encryption")
+
+ def update(self, volume_type, specs):
+ """
+ Update the encryption type information for the specified volume type.
+
+ :param volume_type: the volume type whose encryption type information
+ must be updated
+ :param specs: the encryption type specifications to update
+ :return: an instance of :class: VolumeEncryptionType
+ """
+ body = {'encryption': specs}
+ return self._update("/types/%s/encryption/provider" %
+ base.getid(volume_type), body)
+
+ def delete(self, volume_type):
+ """
+ Delete the encryption type information for the specified volume type.
+
+ :param volume_type: the volume type whose encryption type information
+ must be deleted
+ """
+ return self._delete("/types/%s/encryption/provider" %
+ base.getid(volume_type))
diff --git a/cinderclient/v3/volume_snapshots.py b/cinderclient/v3/volume_snapshots.py
index 3691d2f..ce7f4e0 100644
--- a/cinderclient/v3/volume_snapshots.py
+++ b/cinderclient/v3/volume_snapshots.py
@@ -213,9 +213,17 @@ class SnapshotManager(base.ManagerWithFind):
}
return self._create('/os-snapshot-manage', body, 'snapshot')
+ @api_versions.wraps("3.0")
+ def list_manageable(self, host, detailed=True, marker=None,
+ limit=None, offset=None, sort=None):
+ url = self._build_list_url("os-snapshot-manage", detailed=detailed,
+ search_opts={'host': host}, marker=marker,
+ limit=limit, offset=offset, sort=sort)
+ return self._list(url, "manageable-snapshots")
+
@api_versions.wraps('3.8')
- def list_manageable(self, host, detailed=True, marker=None, limit=None,
- offset=None, sort=None, cluster=None):
+ def list_manageable(self, host, detailed=True, marker=None, # noqa: F811
+ limit=None, offset=None, sort=None, cluster=None):
search_opts = {'cluster': cluster} if cluster else {'host': host}
url = self._build_list_url("manageable_snapshots", detailed=detailed,
search_opts=search_opts, marker=marker,
diff --git a/cinderclient/v3/volume_transfers.py b/cinderclient/v3/volume_transfers.py
index f40c519..bcf0e0c 100644
--- a/cinderclient/v3/volume_transfers.py
+++ b/cinderclient/v3/volume_transfers.py
@@ -16,10 +16,23 @@
"""Volume transfer interface (v3 extension)."""
from cinderclient import base
-from cinderclient.v2 import volume_transfers
-class VolumeTransferManager(volume_transfers.VolumeTransferManager):
+class VolumeTransfer(base.Resource):
+ """Transfer a volume from one tenant to another"""
+
+ def __repr__(self):
+ return "<VolumeTransfer: %s>" % self.id
+
+ def delete(self):
+ """Delete this volume transfer."""
+ return self.manager.delete(self)
+
+
+class VolumeTransferManager(base.ManagerWithFind):
+ """Manage :class:`VolumeTransfer` resources."""
+ resource_class = VolumeTransfer
+
def create(self, volume_id, name=None, no_snapshots=False):
"""Creates a volume transfer.
diff --git a/cinderclient/v3/volume_type_access.py b/cinderclient/v3/volume_type_access.py
index d9fe2ef..bdd2e70 100644
--- a/cinderclient/v3/volume_type_access.py
+++ b/cinderclient/v3/volume_type_access.py
@@ -14,4 +14,40 @@
"""Volume type access interface."""
-from cinderclient.v2.volume_type_access import * # noqa
+from cinderclient.apiclient import base as common_base
+from cinderclient import base
+
+
+class VolumeTypeAccess(base.Resource):
+ def __repr__(self):
+ return "<VolumeTypeAccess: %s>" % self.project_id
+
+
+class VolumeTypeAccessManager(base.ManagerWithFind):
+ """
+ Manage :class:`VolumeTypeAccess` resources.
+ """
+ resource_class = VolumeTypeAccess
+
+ def list(self, volume_type):
+ return self._list(
+ '/types/%s/os-volume-type-access' % base.getid(volume_type),
+ 'volume_type_access')
+
+ def add_project_access(self, volume_type, project):
+ """Add a project to the given volume type access list."""
+ info = {'project': project}
+ return self._action('addProjectAccess', volume_type, info)
+
+ def remove_project_access(self, volume_type, project):
+ """Remove a project from the given volume type access list."""
+ info = {'project': project}
+ return self._action('removeProjectAccess', volume_type, info)
+
+ def _action(self, action, volume_type, info, **kwargs):
+ """Perform a volume type action."""
+ body = {action: info}
+ self.run_hooks('modify_body_for_action', body, **kwargs)
+ url = '/types/%s/action' % base.getid(volume_type)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v3/volumes.py b/cinderclient/v3/volumes.py
index 8ea3880..42527f7 100644
--- a/cinderclient/v3/volumes.py
+++ b/cinderclient/v3/volumes.py
@@ -18,10 +18,10 @@
from cinderclient import api_versions
from cinderclient.apiclient import base as common_base
from cinderclient import base
-from cinderclient.v2 import volumes
+from cinderclient.v3 import volumes_base
-class Volume(volumes.Volume):
+class Volume(volumes_base.Volume):
def upload_to_image(self, force, image_name, container_format,
disk_format, visibility=None,
@@ -68,7 +68,7 @@ class Volume(volumes.Volume):
cluster=cluster)
-class VolumeManager(volumes.VolumeManager):
+class VolumeManager(volumes_base.VolumeManager):
resource_class = Volume
def create(self, size, consistencygroup_id=None,
@@ -246,16 +246,24 @@ class VolumeManager(volumes.VolumeManager):
body['volume']['cluster'] = cluster
return self._create('/os-volume-manage', body, 'volume')
+ @api_versions.wraps('3.0')
+ def list_manageable(self, host, detailed=True, marker=None,
+ limit=None, offset=None, sort=None):
+ url = self._build_list_url("os-volume-manage", detailed=detailed,
+ search_opts={'host': host}, marker=marker,
+ limit=limit, offset=offset, sort=sort)
+ return self._list(url, "manageable-volumes")
+
@api_versions.wraps('3.8')
- def list_manageable(self, host, detailed=True, marker=None, limit=None,
- offset=None, sort=None, cluster=None):
+ def list_manageable(self, host, detailed=True, marker=None, # noqa: F811
+ limit=None, offset=None, sort=None, cluster=None):
search_opts = {'cluster': cluster} if cluster else {'host': host}
url = self._build_list_url("manageable_volumes", detailed=detailed,
search_opts=search_opts, marker=marker,
limit=limit, offset=offset, sort=sort)
return self._list(url, "manageable-volumes")
- @api_versions.wraps("2.0", "3.32")
+ @api_versions.wraps("3.0", "3.32")
def get_pools(self, detail):
"""Show pool information for backends."""
query_string = ""
diff --git a/cinderclient/v2/volumes.py b/cinderclient/v3/volumes_base.py
index 4c380fb..3b00b59 100644
--- a/cinderclient/v2/volumes.py
+++ b/cinderclient/v3/volumes_base.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""Volume interface (v2 extension)."""
+"""Base Volume interface."""
from cinderclient.apiclient import base as common_base
from cinderclient import base
@@ -130,24 +130,6 @@ class Volume(base.Resource):
"""
return self.manager.show_image_metadata(self)
- def upload_to_image(self, force, image_name, container_format,
- disk_format, visibility=None,
- protected=None):
- """Upload a volume to image service as an image.
-
- :param force: Boolean to enables or disables upload of a volume that
- is attached to an instance.
- :param image_name: The new image name.
- :param container_format: Container format type.
- :param disk_format: Disk format type.
- :param visibility: The accessibility of image (allowed for
- 3.1-latest).
- :param protected: Boolean to decide whether prevents image from being
- deleted (allowed for 3.1-latest).
- """
- return self.manager.upload_to_image(self, force, image_name,
- container_format, disk_format)
-
def force_delete(self):
"""Delete the specified volume ignoring its current state.
@@ -175,11 +157,6 @@ class Volume(base.Resource):
"""
return self.manager.extend(self, new_size)
- def migrate_volume(self, host, force_host_copy, lock_volume):
- """Migrate the volume to a new host."""
- return self.manager.migrate_volume(self, host, force_host_copy,
- lock_volume)
-
def retype(self, volume_type, policy):
"""Change a volume's type."""
return self.manager.retype(self, volume_type, policy)
@@ -197,16 +174,6 @@ class Volume(base.Resource):
"""
return self.manager.update_readonly_flag(self, read_only)
- def manage(self, host, ref, name=None, description=None,
- volume_type=None, availability_zone=None, metadata=None,
- bootable=False):
- """Manage an existing volume."""
- return self.manager.manage(host=host, ref=ref, name=name,
- description=description,
- volume_type=volume_type,
- availability_zone=availability_zone,
- metadata=metadata, bootable=bootable)
-
def list_manageable(self, host, detailed=True, marker=None, limit=None,
offset=None, sort=None):
return self.manager.list_manageable(host, detailed=detailed,
@@ -226,52 +193,6 @@ class VolumeManager(base.ManagerWithFind):
"""Manage :class:`Volume` resources."""
resource_class = Volume
- def create(self, size, consistencygroup_id=None,
- snapshot_id=None,
- source_volid=None, name=None, description=None,
- volume_type=None, user_id=None,
- project_id=None, availability_zone=None,
- metadata=None, imageRef=None, scheduler_hints=None):
- """Create a volume.
-
- :param size: Size of volume in GB
- :param consistencygroup_id: ID of the consistencygroup
- :param snapshot_id: ID of the snapshot
- :param name: Name of the volume
- :param description: Description of the volume
- :param volume_type: Type of volume
- :param user_id: User id derived from context (IGNORED)
- :param project_id: Project id derived from context (IGNORED)
- :param availability_zone: Availability Zone to use
- :param metadata: Optional metadata to set on volume creation
- :param imageRef: reference to an image stored in glance
- :param source_volid: ID of source volume to clone from
- :param scheduler_hints: (optional extension) arbitrary key-value pairs
- specified by the client to help boot an instance
- :rtype: :class:`Volume`
- """
- if metadata is None:
- volume_metadata = {}
- else:
- volume_metadata = metadata
-
- body = {'volume': {'size': size,
- 'consistencygroup_id': consistencygroup_id,
- 'snapshot_id': snapshot_id,
- 'name': name,
- 'description': description,
- 'volume_type': volume_type,
- 'availability_zone': availability_zone,
- 'metadata': volume_metadata,
- 'imageRef': imageRef,
- 'source_volid': source_volid,
- }}
-
- if scheduler_hints:
- body['OS-SCH-HNT:scheduler_hints'] = scheduler_hints
-
- return self._create('/volumes', body, 'volume')
-
def get(self, volume_id):
"""Get a volume.
@@ -603,13 +524,6 @@ class VolumeManager(base.ManagerWithFind):
}}
return self._create('/os-volume-manage', body, 'volume')
- def list_manageable(self, host, detailed=True, marker=None, limit=None,
- offset=None, sort=None):
- url = self._build_list_url("os-volume-manage", detailed=detailed,
- search_opts={'host': host}, marker=marker,
- limit=limit, offset=offset, sort=sort)
- return self._list(url, "manageable-volumes")
-
def unmanage(self, volume):
"""Unmanage a volume."""
return self._action('os-unmanage', volume, None)
diff --git a/doc/source/contributor/unit_tests.rst b/doc/source/contributor/unit_tests.rst
index 387ecb0..248e1be 100644
--- a/doc/source/contributor/unit_tests.rst
+++ b/doc/source/contributor/unit_tests.rst
@@ -29,11 +29,11 @@ Running a subset of tests using tox
One common activity is to just run a single test, you can do this with tox
simply by specifying to just run py3 tests against a single test::
- tox -e py3 -- -n cinderclient.tests.unit.v2.test_volumes.VolumesTest.test_attach
+ tox -e py3 -- -n cinderclient.tests.unit.v3.test_volumes.VolumesTest.test_create_volume
Or all tests in the test_volumes.py file::
- tox -e py3 -- -n cinderclient.tests.unit.v2.test_volumes
+ tox -e py3 -- -n cinderclient.tests.unit.v3.test_volumes
For more information on these options and how to run tests, please see the
`stestr documentation <https://stestr.readthedocs.io/en/latest/index.html>`_.
diff --git a/releasenotes/notes/drop-v2-support-e578ca21c7c6b532.yaml b/releasenotes/notes/drop-v2-support-e578ca21c7c6b532.yaml
new file mode 100644
index 0000000..8360a60
--- /dev/null
+++ b/releasenotes/notes/drop-v2-support-e578ca21c7c6b532.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+ - |
+ This release drops support of the Block Storage API v2. The last version
+ of the python-cinderclient supporting that API is the 7.x series.