summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
authorStephen Finucane <sfinucan@redhat.com>2021-05-26 15:04:28 +0100
committerStephen Finucane <sfinucan@redhat.com>2022-05-13 12:42:16 +0100
commit53a7e67b4132281c9e217061aac03429a77f869c (patch)
tree0da45168002016e3e40f89e4cff863072a927d5f /openstackclient
parentd727a6502369a6a7244ef1c07c1c483dbe0a8dab (diff)
downloadpython-openstackclient-53a7e67b4132281c9e217061aac03429a77f869c.tar.gz
volume: Add 'block storage resource filter list' command
These are based on the 'cinder list-filters' command, which accepts an optional '--resource {resource}' option to limit the listed filters to a single resource type. block storage resource filter list block storage resource filter show We used the 'block storage resource filter' terminology rather than simply 'resource filter' to highlight the fact that this is specific to the block storage service. Note that while this feature is a bit weird, good documentation can be found at [1]. [1] https://docs.openstack.org/cinder/latest/admin/generalized_filters.html Change-Id: I21e7c0ea427aef1f6665394d4b8e9a1f30d6dbb1 Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/tests/unit/volume/v3/fakes.py55
-rw-r--r--openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py144
-rw-r--r--openstackclient/volume/v3/block_storage_resource_filter.py83
3 files changed, 278 insertions, 4 deletions
diff --git a/openstackclient/tests/unit/volume/v3/fakes.py b/openstackclient/tests/unit/volume/v3/fakes.py
index 81ff0a98..e27d7fca 100644
--- a/openstackclient/tests/unit/volume/v3/fakes.py
+++ b/openstackclient/tests/unit/volume/v3/fakes.py
@@ -42,6 +42,8 @@ class FakeVolumeClient(object):
self.group_types.resource_class = fakes.FakeResource(None, {})
self.messages = mock.Mock()
self.messages.resource_class = fakes.FakeResource(None, {})
+ self.resource_filters = mock.Mock()
+ self.resource_filters.resource_class = fakes.FakeResource(None, {})
self.volumes = mock.Mock()
self.volumes.resource_class = fakes.FakeResource(None, {})
self.volume_types = mock.Mock()
@@ -124,6 +126,53 @@ class FakeCluster:
return clusters
+class FakeResourceFilter:
+ """Fake one or more resource filters."""
+
+ @staticmethod
+ def create_one_resource_filter(attrs=None):
+ """Create a fake resource filter.
+
+ :param attrs: A dictionary with all attributes of resource filter
+ :return: A FakeResource object with id, name, status, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attribute
+
+ resource_filter_info = {
+ 'filters': [
+ 'name',
+ 'status',
+ 'image_metadata',
+ 'bootable',
+ 'migration_status',
+ ],
+ 'resource': 'volume',
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ resource_filter_info.update(attrs)
+
+ return fakes.FakeResource(None, resource_filter_info, loaded=True)
+
+ @staticmethod
+ def create_resource_filters(attrs=None, count=2):
+ """Create multiple fake resource filters.
+
+ :param attrs: A dictionary with all attributes of resource filter
+ :param count: The number of resource filters to be faked
+ :return: A list of FakeResource objects
+ """
+ resource_filters = []
+ for n in range(0, count):
+ resource_filters.append(
+ FakeResourceFilter.create_one_resource_filter(attrs)
+ )
+
+ return resource_filters
+
+
class FakeVolumeGroup:
"""Fake one or more volume groups."""
@@ -309,11 +358,10 @@ class FakeVolumeMessage:
# Overwrite default attributes if there are some attributes set
message_info.update(attrs)
- message = fakes.FakeResource(
+ return fakes.FakeResource(
None,
message_info,
loaded=True)
- return message
@staticmethod
def create_volume_messages(attrs=None, count=2):
@@ -402,11 +450,10 @@ class FakeVolumeAttachment:
# Overwrite default attributes if there are some attributes set
attachment_info.update(attrs)
- attachment = fakes.FakeResource(
+ return fakes.FakeResource(
None,
attachment_info,
loaded=True)
- return attachment
@staticmethod
def create_volume_attachments(attrs=None, count=2):
diff --git a/openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py b/openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py
new file mode 100644
index 00000000..b886726d
--- /dev/null
+++ b/openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py
@@ -0,0 +1,144 @@
+# 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 api_versions
+from osc_lib import exceptions
+
+from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
+from openstackclient.volume.v3 import block_storage_resource_filter
+
+
+class TestBlockStorageResourceFilter(volume_fakes.TestVolume):
+
+ def setUp(self):
+ super().setUp()
+
+ # Get a shortcut to the ResourceFilterManager Mock
+ self.resource_filter_mock = \
+ self.app.client_manager.volume.resource_filters
+ self.resource_filter_mock.reset_mock()
+
+
+class TestBlockStorageResourceFilterList(TestBlockStorageResourceFilter):
+
+ # The resource filters to be listed
+ fake_resource_filters = \
+ volume_fakes.FakeResourceFilter.create_resource_filters()
+
+ def setUp(self):
+ super().setUp()
+
+ self.resource_filter_mock.list.return_value = \
+ self.fake_resource_filters
+
+ # Get the command object to test
+ self.cmd = block_storage_resource_filter\
+ .ListBlockStorageResourceFilter(self.app, None)
+
+ def test_resource_filter_list(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.33')
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ expected_columns = ('Resource', 'Filters')
+ expected_data = tuple(
+ (
+ resource_filter.resource,
+ resource_filter.filters,
+ ) for resource_filter in self.fake_resource_filters
+ )
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, tuple(data))
+
+ # checking if proper call was made to list clusters
+ self.resource_filter_mock.list.assert_called_with()
+
+ def test_resource_filter_list_pre_v333(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.32')
+
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.33 or greater is required', str(exc))
+
+
+class TestBlockStorageResourceFilterShow(TestBlockStorageResourceFilter):
+
+ # The resource filters to be listed
+ fake_resource_filter = \
+ volume_fakes.FakeResourceFilter.create_one_resource_filter()
+
+ def setUp(self):
+ super().setUp()
+
+ self.resource_filter_mock.list.return_value = \
+ iter([self.fake_resource_filter])
+
+ # Get the command object to test
+ self.cmd = block_storage_resource_filter\
+ .ShowBlockStorageResourceFilter(self.app, None)
+
+ def test_resource_filter_show(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.33')
+
+ arglist = [
+ self.fake_resource_filter.resource,
+ ]
+ verifylist = [
+ ('resource', self.fake_resource_filter.resource),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ expected_columns = ('filters', 'resource')
+ expected_data = (
+ self.fake_resource_filter.filters,
+ self.fake_resource_filter.resource,
+ )
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(expected_columns, columns)
+ self.assertEqual(expected_data, data)
+
+ # checking if proper call was made to list clusters
+ self.resource_filter_mock.list.assert_called_with(resource='volume')
+
+ def test_resource_filter_show_pre_v333(self):
+ self.app.client_manager.volume.api_version = \
+ api_versions.APIVersion('3.32')
+
+ arglist = [
+ self.fake_resource_filter.resource,
+ ]
+ verifylist = [
+ ('resource', self.fake_resource_filter.resource),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ exc = self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+ self.assertIn(
+ '--os-volume-api-version 3.33 or greater is required', str(exc))
diff --git a/openstackclient/volume/v3/block_storage_resource_filter.py b/openstackclient/volume/v3/block_storage_resource_filter.py
new file mode 100644
index 00000000..4bcacf90
--- /dev/null
+++ b/openstackclient/volume/v3/block_storage_resource_filter.py
@@ -0,0 +1,83 @@
+# 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 V3 Resource Filters implementations"""
+
+from cinderclient import api_versions
+from osc_lib.command import command
+from osc_lib import exceptions
+from osc_lib import utils
+
+from openstackclient.i18n import _
+
+
+class ListBlockStorageResourceFilter(command.Lister):
+ _description = _('List block storage resource filters')
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+
+ if volume_client.api_version < api_versions.APIVersion('3.33'):
+ msg = _(
+ "--os-volume-api-version 3.33 or greater is required to "
+ "support the 'block storage resource filter list' command"
+ )
+ raise exceptions.CommandError(msg)
+
+ column_headers = (
+ 'Resource',
+ 'Filters',
+ )
+
+ data = volume_client.resource_filters.list()
+
+ return (
+ column_headers,
+ (utils.get_item_properties(s, column_headers) for s in data)
+ )
+
+
+class ShowBlockStorageResourceFilter(command.ShowOne):
+ _description = _('Show filters for a block storage resource type')
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ parser.add_argument(
+ 'resource',
+ metavar='<resource>',
+ help=_('Resource to show filters for (name).')
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+
+ if volume_client.api_version < api_versions.APIVersion('3.33'):
+ msg = _(
+ "--os-volume-api-version 3.33 or greater is required to "
+ "support the 'block storage resource filter show' command"
+ )
+ raise exceptions.CommandError(msg)
+
+ data = volume_client.resource_filters.list(
+ resource=parsed_args.resource
+ )
+ if not data:
+ msg = _(
+ "No resource filter with a name of {parsed_args.resource}' "
+ "exists."
+ )
+ raise exceptions.CommandError(msg)
+ resource_filter = next(data)
+
+ return zip(*sorted(resource_filter._info.items()))