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:
parent
d727a65023
commit
53a7e67b41
@ -0,0 +1,8 @@
|
||||
=============================
|
||||
block storage resource filter
|
||||
=============================
|
||||
|
||||
Block Storage v3
|
||||
|
||||
.. autoprogram-cliff:: openstack.volume.v3
|
||||
:command: block storage resource filter *
|
@ -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
|
||||
|
@ -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)
|
||||
|
|
@ -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):
|
||||
|
@ -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))
|
83
openstackclient/volume/v3/block_storage_resource_filter.py
Normal file
83
openstackclient/volume/v3/block_storage_resource_filter.py
Normal 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()))
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user