From 1a8cd8419946e2d9374d6269220181e49df61ed0 Mon Sep 17 00:00:00 2001 From: Steven Relf Date: Thu, 21 Sep 2017 14:53:51 +0100 Subject: [PATCH] Adds support to retrieve cinder backend pools information This code additiona allows the collection of cinder backend pool stats directly from the api. This eliminates the need to poll for this data directly from ceph or other storage services. Change-Id: Iabf7a6a5143fc61ec044d6b672a18cfc951219d7 --- doc/source/users/proxies/block_storage.rst | 7 +++ openstack/block_storage/v2/_proxy.py | 8 ++++ openstack/block_storage/v2/stats.py | 34 ++++++++++++++ .../functional/block_store/v2/test_stats.py | 45 ++++++++++++++++++ .../tests/unit/block_storage/v2/test_proxy.py | 5 ++ .../tests/unit/block_store/v2/test_stats.py | 47 +++++++++++++++++++ 6 files changed, 146 insertions(+) create mode 100644 openstack/block_storage/v2/stats.py create mode 100644 openstack/tests/functional/block_store/v2/test_stats.py create mode 100644 openstack/tests/unit/block_store/v2/test_stats.py diff --git a/doc/source/users/proxies/block_storage.rst b/doc/source/users/proxies/block_storage.rst index 460624151..ba9f7e355 100644 --- a/doc/source/users/proxies/block_storage.rst +++ b/doc/source/users/proxies/block_storage.rst @@ -41,3 +41,10 @@ Snapshot Operations .. automethod:: openstack.block_storage.v2._proxy.Proxy.delete_snapshot .. automethod:: openstack.block_storage.v2._proxy.Proxy.get_snapshot .. automethod:: openstack.block_storage.v2._proxy.Proxy.snapshots + +Stats Operations +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: openstack.block_storage.v2._proxy.Proxy + + .. automethod:: openstack.block_storage.v2._proxy.Proxy.backend_pools diff --git a/openstack/block_storage/v2/_proxy.py b/openstack/block_storage/v2/_proxy.py index 202a2d8a0..90bb623b3 100644 --- a/openstack/block_storage/v2/_proxy.py +++ b/openstack/block_storage/v2/_proxy.py @@ -11,6 +11,7 @@ # under the License. from openstack.block_storage.v2 import snapshot as _snapshot +from openstack.block_storage.v2 import stats as _stats from openstack.block_storage.v2 import type as _type from openstack.block_storage.v2 import volume as _volume from openstack import proxy2 @@ -187,3 +188,10 @@ class Proxy(proxy2.BaseProxy): :returns: ``None`` """ self._delete(_volume.Volume, volume, ignore_missing=ignore_missing) + + def backend_pools(self): + """Returns a generator of cinder Back-end storage pools + + :returns A generator of cinder Back-end storage pools objects + """ + return self._list(_stats.Pools, paginated=False) diff --git a/openstack/block_storage/v2/stats.py b/openstack/block_storage/v2/stats.py new file mode 100644 index 000000000..80a9c0b60 --- /dev/null +++ b/openstack/block_storage/v2/stats.py @@ -0,0 +1,34 @@ +# 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 openstack.block_storage import block_storage_service +from openstack import resource2 + + +class Pools(resource2.Resource): + resource_key = "pool" + resources_key = "pools" + base_path = "/scheduler-stats/get_pools?detail=True" + service = block_storage_service.BlockStorageService() + + # capabilities + allow_get = False + allow_create = False + allow_delete = False + allow_list = True + + # Properties + #: The Cinder name for the pool + name = resource2.Body("name") + #: returns a dict with information about the pool + capabilities = resource2.Body("capabilities", + type=dict) diff --git a/openstack/tests/functional/block_store/v2/test_stats.py b/openstack/tests/functional/block_store/v2/test_stats.py new file mode 100644 index 000000000..581f6e33e --- /dev/null +++ b/openstack/tests/functional/block_store/v2/test_stats.py @@ -0,0 +1,45 @@ +# 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 openstack.block_storage.v2 import stats as _stats +from openstack.tests.functional import base + + +class TestStats(base.BaseFunctionalTest): + + @classmethod + def setUpClass(cls): + super(TestStats, cls).setUpClass() + sot = cls.conn.block_storage.backend_pools() + for pool in sot: + assert isinstance(pool, _stats.Pools) + + def test_list(self): + capList = ['volume_backend_name', 'storage_protocol', + 'free_capacity_gb', 'driver_version', + 'goodness_function', 'QoS_support', + 'vendor_name', 'pool_name', 'thin_provisioning_support', + 'thick_provisioning_support', 'timestamp', + 'max_over_subscription_ratio', 'total_volumes', + 'total_capacity_gb', 'filter_function', + 'multiattach', 'provisioned_capacity_gb', + 'allocated_capacity_gb', 'reserved_percentage', + 'location_info'] + capList.sort() + pools = self.conn.block_storage.backend_pools() + for pool in pools: + caps = pool.capabilities + keys = caps.keys() + keys.sort() + assert isinstance(caps, dict) + self.assertListEqual(keys, capList) diff --git a/openstack/tests/unit/block_storage/v2/test_proxy.py b/openstack/tests/unit/block_storage/v2/test_proxy.py index 431b5f48a..ac616e89d 100644 --- a/openstack/tests/unit/block_storage/v2/test_proxy.py +++ b/openstack/tests/unit/block_storage/v2/test_proxy.py @@ -12,6 +12,7 @@ from openstack.block_storage.v2 import _proxy from openstack.block_storage.v2 import snapshot +from openstack.block_storage.v2 import stats from openstack.block_storage.v2 import type from openstack.block_storage.v2 import volume from openstack.tests.unit import test_proxy_base2 @@ -86,3 +87,7 @@ class TestVolumeProxy(test_proxy_base2.TestProxyBase): def test_volume_delete_ignore(self): self.verify_delete(self.proxy.delete_volume, volume.Volume, True) + + def test_backend_pools(self): + self.verify_list(self.proxy.backend_pools, stats.Pools, + paginated=False) diff --git a/openstack/tests/unit/block_store/v2/test_stats.py b/openstack/tests/unit/block_store/v2/test_stats.py new file mode 100644 index 000000000..a8991a81b --- /dev/null +++ b/openstack/tests/unit/block_store/v2/test_stats.py @@ -0,0 +1,47 @@ +# 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 testtools + +from openstack.block_storage.v2 import stats + +POOLS = {"name": "pool1", + "capabilities": { + "updated": "2014-10-28T00=00=00-00=00", + "total_capacity": 1024, + "free_capacity": 100, + "volume_backend_name": "pool1", + "reserved_percentage": "0", + "driver_version": "1.0.0", + "storage_protocol": "iSCSI", + "QoS_support": "false" + } + } + + +class TestBackendPools(testtools.TestCase): + + def setUp(self): + super(TestBackendPools, self).setUp() + + def test_basic(self): + sot = stats.Pools(POOLS) + self.assertEqual("pool", sot.resource_key) + self.assertEqual("pools", sot.resources_key) + self.assertEqual("/scheduler-stats/get_pools?detail=True", + sot.base_path) + self.assertEqual("volume", sot.service.service_type) + self.assertFalse(sot.allow_create) + self.assertFalse(sot.allow_get) + self.assertFalse(sot.allow_delete) + self.assertTrue(sot.allow_list) + self.assertFalse(sot.allow_update)