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>
This commit is contained in:
Stephen Finucane 2021-05-26 15:04:28 +01:00
parent d727a65023
commit 53a7e67b41
7 changed files with 290 additions and 5 deletions

View File

@ -0,0 +1,8 @@
=============================
block storage resource filter
=============================
Block Storage v3
.. autoprogram-cliff:: openstack.volume.v3
:command: block storage resource filter *

View File

@ -77,6 +77,7 @@ referring to both Compute and Volume quotas.
* ``aggregate``: (**Compute**) a grouping of compute hosts
* ``availability zone``: (**Compute**, **Network**, **Volume**) a logical partition of hosts or block storage or network services
* ``block storage cluster``: (**Volume**) clusters of volume services
* ``block storage resource filter``: (**Volume**) filters for volume service resources
* ``catalog``: (**Identity**) service catalog
* ``command``: (**Internal**) installed commands in the OSC process
* ``compute agent``: (**Compute**) a cloud Compute agent available to a hypervisor

View File

@ -69,7 +69,7 @@ group-update,volume group set,Updates a group. (Supported by API versions 3.13 -
image-metadata,volume set --image-property,Sets or deletes volume image metadata.
image-metadata-show,volume show,Shows volume image metadata.
list,volume list,Lists all volumes.
list-filters,,List enabled filters. (Supported by API versions 3.33 - 3.latest)
list-filters,block storage resource filter list,List enabled filters. (Supported by API versions 3.33 - 3.latest)
manage,volume create --remote-source k=v,Manage an existing volume.
manageable-list,,Lists all manageable volumes. (Supported by API versions 3.8 - 3.latest)
message-delete,volume message delete,Removes one or more messages. (Supported by API versions 3.3 - 3.latest)

1 absolute-limits limits show --absolute Lists absolute limits for a user.
69 image-metadata volume set --image-property Sets or deletes volume image metadata.
70 image-metadata-show volume show Shows volume image metadata.
71 list volume list Lists all volumes.
72 list-filters block storage resource filter list List enabled filters. (Supported by API versions 3.33 - 3.latest)
73 manage volume create --remote-source k=v Manage an existing volume.
74 manageable-list Lists all manageable volumes. (Supported by API versions 3.8 - 3.latest)
75 message-delete volume message delete Removes one or more messages. (Supported by API versions 3.3 - 3.latest)

View File

@ -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):

View File

@ -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))

View File

@ -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()))

View File

@ -759,6 +759,8 @@ openstack.volume.v3 =
block_storage_cluster_list = openstackclient.volume.v3.block_storage_cluster:ListBlockStorageCluster
block_storage_cluster_set = openstackclient.volume.v3.block_storage_cluster:SetBlockStorageCluster
block_storage_cluster_show = openstackclient.volume.v3.block_storage_cluster:ShowBlockStorageCluster
block_storage_resource_filter_list = openstackclient.volume.v3.block_storage_resource_filter:ListBlockStorageResourceFilter
block_storage_resource_filter_show = openstackclient.volume.v3.block_storage_resource_filter:ShowBlockStorageResourceFilter
volume_snapshot_create = openstackclient.volume.v2.volume_snapshot:CreateVolumeSnapshot
volume_snapshot_delete = openstackclient.volume.v2.volume_snapshot:DeleteVolumeSnapshot