mirror of
https://opendev.org/openstack/python-openstackclient.git
synced 2026-01-16 23:13:05 +00:00
Merge "volume: Add 'volume message *' commands"
This commit is contained in:
commit
ae5f3009d5
8 changed files with 579 additions and 3 deletions
8
doc/source/cli/command-objects/volume-message.rst
Normal file
8
doc/source/cli/command-objects/volume-message.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
==============
|
||||
volume message
|
||||
==============
|
||||
|
||||
Block Storage v3
|
||||
|
||||
.. autoprogram-cliff:: openstack.volume.v3
|
||||
:command: volume message *
|
||||
|
|
@ -160,6 +160,7 @@ referring to both Compute and Volume quotas.
|
|||
* ``volume backup record``: (**Volume**) volume record that can be imported or exported
|
||||
* ``volume backend``: (**Volume**) volume backend storage
|
||||
* ``volume host``: (**Volume**) the physical computer for volumes
|
||||
* ``volume message``: (**Volume**) volume API internal messages detailing volume failure messages
|
||||
* ``volume qos``: (**Volume**) quality-of-service (QoS) specification for volumes
|
||||
* ``volume snapshot``: (**Volume**) a point-in-time copy of a volume
|
||||
* ``volume type``: (**Volume**) deployment-specific types of volumes available
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ list,volume list,Lists all volumes.
|
|||
list-filters,,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,,Removes one or more messages. (Supported by API versions 3.3 - 3.latest)
|
||||
message-list,,Lists all messages. (Supported by API versions 3.3 - 3.latest)
|
||||
message-show,,Shows message details. (Supported by API versions 3.3 - 3.latest)
|
||||
message-delete,volume message delete,Removes one or more messages. (Supported by API versions 3.3 - 3.latest)
|
||||
message-list,volume message list,Lists all messages. (Supported by API versions 3.3 - 3.latest)
|
||||
message-show,volume message show,Shows message details. (Supported by API versions 3.3 - 3.latest)
|
||||
metadata,volume set --property k=v / volume unset --property k,Sets or deletes volume metadata.
|
||||
metadata-show,volume show,Shows volume metadata.
|
||||
metadata-update-all,volume set --property k=v,Updates volume metadata.
|
||||
|
|
|
|||
|
|
|
@ -32,6 +32,8 @@ class FakeVolumeClient(object):
|
|||
|
||||
self.attachments = mock.Mock()
|
||||
self.attachments.resource_class = fakes.FakeResource(None, {})
|
||||
self.messages = mock.Mock()
|
||||
self.messages.resource_class = fakes.FakeResource(None, {})
|
||||
self.volumes = mock.Mock()
|
||||
self.volumes.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
|
|
@ -59,6 +61,72 @@ class TestVolume(utils.TestCommand):
|
|||
FakeVolume = volume_v2_fakes.FakeVolume
|
||||
|
||||
|
||||
class FakeVolumeMessage:
|
||||
"""Fake one or more volume messages."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_volume_message(attrs=None):
|
||||
"""Create a fake message.
|
||||
|
||||
:param attrs: A dictionary with all attributes of message
|
||||
:return: A FakeResource object with id, name, status, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attribute
|
||||
message_info = {
|
||||
'created_at': '2016-02-11T11:17:37.000000',
|
||||
'event_id': f'VOLUME_{random.randint(1, 999999):06d}',
|
||||
'guaranteed_until': '2016-02-11T11:17:37.000000',
|
||||
'id': uuid.uuid4().hex,
|
||||
'message_level': 'ERROR',
|
||||
'request_id': f'req-{uuid.uuid4().hex}',
|
||||
'resource_type': 'VOLUME',
|
||||
'resource_uuid': uuid.uuid4().hex,
|
||||
'user_message': f'message-{uuid.uuid4().hex}',
|
||||
}
|
||||
|
||||
# Overwrite default attributes if there are some attributes set
|
||||
message_info.update(attrs)
|
||||
|
||||
message = fakes.FakeResource(
|
||||
None,
|
||||
message_info,
|
||||
loaded=True)
|
||||
return message
|
||||
|
||||
@staticmethod
|
||||
def create_volume_messages(attrs=None, count=2):
|
||||
"""Create multiple fake messages.
|
||||
|
||||
:param attrs: A dictionary with all attributes of message
|
||||
:param count: The number of messages to be faked
|
||||
:return: A list of FakeResource objects
|
||||
"""
|
||||
messages = []
|
||||
for n in range(0, count):
|
||||
messages.append(FakeVolumeMessage.create_one_volume_message(attrs))
|
||||
|
||||
return messages
|
||||
|
||||
@staticmethod
|
||||
def get_volume_messages(messages=None, count=2):
|
||||
"""Get an iterable MagicMock object with a list of faked messages.
|
||||
|
||||
If messages list is provided, then initialize the Mock object with the
|
||||
list. Otherwise create one.
|
||||
|
||||
:param messages: A list of FakeResource objects faking messages
|
||||
:param count: The number of messages to be faked
|
||||
:return An iterable Mock object with side_effect set to a list of faked
|
||||
messages
|
||||
"""
|
||||
if messages is None:
|
||||
messages = FakeVolumeMessage.create_messages(count)
|
||||
|
||||
return mock.Mock(side_effect=messages)
|
||||
|
||||
|
||||
class FakeVolumeAttachment:
|
||||
"""Fake one or more volume attachments."""
|
||||
|
||||
|
|
|
|||
324
openstackclient/tests/unit/volume/v3/test_volume_message.py
Normal file
324
openstackclient/tests/unit/volume/v3/test_volume_message.py
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
# 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 unittest.mock import call
|
||||
|
||||
from cinderclient import api_versions
|
||||
from osc_lib import exceptions
|
||||
|
||||
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
|
||||
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
|
||||
from openstackclient.volume.v3 import volume_message
|
||||
|
||||
|
||||
class TestVolumeMessage(volume_fakes.TestVolume):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.projects_mock = self.app.client_manager.identity.projects
|
||||
self.projects_mock.reset_mock()
|
||||
|
||||
self.volume_messages_mock = self.app.client_manager.volume.messages
|
||||
self.volume_messages_mock.reset_mock()
|
||||
|
||||
|
||||
class TestVolumeMessageDelete(TestVolumeMessage):
|
||||
|
||||
fake_messages = volume_fakes.FakeVolumeMessage.create_volume_messages(
|
||||
count=2)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.volume_messages_mock.get = \
|
||||
volume_fakes.FakeVolumeMessage.get_volume_messages(
|
||||
self.fake_messages)
|
||||
self.volume_messages_mock.delete.return_value = None
|
||||
|
||||
# Get the command object to mock
|
||||
self.cmd = volume_message.DeleteMessage(self.app, None)
|
||||
|
||||
def test_message_delete(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = [
|
||||
self.fake_messages[0].id,
|
||||
]
|
||||
verifylist = [
|
||||
('message_ids', [self.fake_messages[0].id]),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.volume_messages_mock.delete.assert_called_with(
|
||||
self.fake_messages[0].id)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_message_delete_multiple_messages(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = [
|
||||
self.fake_messages[0].id,
|
||||
self.fake_messages[1].id,
|
||||
]
|
||||
verifylist = [
|
||||
('message_ids', arglist),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
calls = []
|
||||
for m in self.fake_messages:
|
||||
calls.append(call(m.id))
|
||||
self.volume_messages_mock.delete.assert_has_calls(calls)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_message_delete_multiple_messages_with_exception(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = [
|
||||
self.fake_messages[0].id,
|
||||
'invalid_message',
|
||||
]
|
||||
verifylist = [
|
||||
('message_ids', arglist),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.volume_messages_mock.delete.side_effect = [
|
||||
self.fake_messages[0], exceptions.CommandError]
|
||||
|
||||
exc = self.assertRaises(
|
||||
exceptions.CommandError,
|
||||
self.cmd.take_action, parsed_args)
|
||||
self.assertEqual('Failed to delete 1 of 2 messages.', str(exc))
|
||||
|
||||
self.volume_messages_mock.delete.assert_any_call(
|
||||
self.fake_messages[0].id)
|
||||
self.volume_messages_mock.delete.assert_any_call('invalid_message')
|
||||
|
||||
self.assertEqual(2, self.volume_messages_mock.delete.call_count)
|
||||
|
||||
def test_message_delete_pre_v33(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.2')
|
||||
|
||||
arglist = [
|
||||
self.fake_messages[0].id,
|
||||
]
|
||||
verifylist = [
|
||||
('message_ids', [self.fake_messages[0].id]),
|
||||
]
|
||||
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.3 or greater is required',
|
||||
str(exc))
|
||||
|
||||
|
||||
class TestVolumeMessageList(TestVolumeMessage):
|
||||
|
||||
fake_project = identity_fakes.FakeProject.create_one_project()
|
||||
fake_messages = volume_fakes.FakeVolumeMessage.create_volume_messages(
|
||||
count=3)
|
||||
|
||||
columns = (
|
||||
'ID',
|
||||
'Event ID',
|
||||
'Resource Type',
|
||||
'Resource UUID',
|
||||
'Message Level',
|
||||
'User Message',
|
||||
'Request ID',
|
||||
'Created At',
|
||||
'Guaranteed Until',
|
||||
)
|
||||
data = []
|
||||
for fake_message in fake_messages:
|
||||
data.append((
|
||||
fake_message.id,
|
||||
fake_message.event_id,
|
||||
fake_message.resource_type,
|
||||
fake_message.resource_uuid,
|
||||
fake_message.message_level,
|
||||
fake_message.user_message,
|
||||
fake_message.request_id,
|
||||
fake_message.created_at,
|
||||
fake_message.guaranteed_until,
|
||||
))
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.projects_mock.get.return_value = self.fake_project
|
||||
self.volume_messages_mock.list.return_value = self.fake_messages
|
||||
# Get the command to test
|
||||
self.cmd = volume_message.ListMessages(self.app, None)
|
||||
|
||||
def test_message_list(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = []
|
||||
verifylist = [
|
||||
('project', None),
|
||||
('marker', None),
|
||||
('limit', None),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
search_opts = {
|
||||
'project_id': None,
|
||||
}
|
||||
self.volume_messages_mock.list.assert_called_with(
|
||||
search_opts=search_opts,
|
||||
marker=None,
|
||||
limit=None,
|
||||
)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertItemsEqual(self.data, list(data))
|
||||
|
||||
def test_message_list_with_options(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = [
|
||||
'--project', self.fake_project.name,
|
||||
'--marker', self.fake_messages[0].id,
|
||||
'--limit', '3',
|
||||
]
|
||||
verifylist = [
|
||||
('project', self.fake_project.name),
|
||||
('marker', self.fake_messages[0].id),
|
||||
('limit', 3),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
search_opts = {
|
||||
'project_id': self.fake_project.id,
|
||||
}
|
||||
self.volume_messages_mock.list.assert_called_with(
|
||||
search_opts=search_opts,
|
||||
marker=self.fake_messages[0].id,
|
||||
limit=3,
|
||||
)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertItemsEqual(self.data, list(data))
|
||||
|
||||
def test_message_list_pre_v33(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.2')
|
||||
|
||||
arglist = []
|
||||
verifylist = [
|
||||
('project', None),
|
||||
('marker', None),
|
||||
('limit', None),
|
||||
]
|
||||
|
||||
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.3 or greater is required',
|
||||
str(exc))
|
||||
|
||||
|
||||
class TestVolumeMessageShow(TestVolumeMessage):
|
||||
|
||||
fake_message = volume_fakes.FakeVolumeMessage.create_one_volume_message()
|
||||
|
||||
columns = (
|
||||
'created_at',
|
||||
'event_id',
|
||||
'guaranteed_until',
|
||||
'id',
|
||||
'message_level',
|
||||
'request_id',
|
||||
'resource_type',
|
||||
'resource_uuid',
|
||||
'user_message',
|
||||
)
|
||||
data = (
|
||||
fake_message.created_at,
|
||||
fake_message.event_id,
|
||||
fake_message.guaranteed_until,
|
||||
fake_message.id,
|
||||
fake_message.message_level,
|
||||
fake_message.request_id,
|
||||
fake_message.resource_type,
|
||||
fake_message.resource_uuid,
|
||||
fake_message.user_message,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.volume_messages_mock.get.return_value = self.fake_message
|
||||
# Get the command object to test
|
||||
self.cmd = volume_message.ShowMessage(self.app, None)
|
||||
|
||||
def test_message_show(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.3')
|
||||
|
||||
arglist = [
|
||||
self.fake_message.id
|
||||
]
|
||||
verifylist = [
|
||||
('message_id', self.fake_message.id)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.volume_messages_mock.get.assert_called_with(self.fake_message.id)
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.data, data)
|
||||
|
||||
def test_message_show_pre_v33(self):
|
||||
self.app.client_manager.volume.api_version = \
|
||||
api_versions.APIVersion('3.2')
|
||||
|
||||
arglist = [
|
||||
self.fake_message.id
|
||||
]
|
||||
verifylist = [
|
||||
('message_id', self.fake_message.id)
|
||||
]
|
||||
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.3 or greater is required',
|
||||
str(exc))
|
||||
165
openstackclient/volume/v3/volume_message.py
Normal file
165
openstackclient/volume/v3/volume_message.py
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#
|
||||
# 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 Messages implementations"""
|
||||
|
||||
import logging as LOG
|
||||
|
||||
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 _
|
||||
from openstackclient.identity import common as identity_common
|
||||
|
||||
|
||||
class DeleteMessage(command.Command):
|
||||
_description = _('Delete a volume failure message')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'message_ids',
|
||||
metavar='<message-id>',
|
||||
nargs='+',
|
||||
help=_('Message(s) to delete (ID)')
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
volume_client = self.app.client_manager.volume
|
||||
|
||||
if volume_client.api_version < api_versions.APIVersion('3.3'):
|
||||
msg = _(
|
||||
"--os-volume-api-version 3.3 or greater is required to "
|
||||
"support the 'volume message delete' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
errors = 0
|
||||
for message_id in parsed_args.message_ids:
|
||||
try:
|
||||
volume_client.messages.delete(message_id)
|
||||
except Exception:
|
||||
LOG.error(_('Failed to delete message: %s'), message_id)
|
||||
errors += 1
|
||||
|
||||
if errors > 0:
|
||||
total = len(parsed_args.message_ids)
|
||||
msg = _('Failed to delete %(errors)s of %(total)s messages.') % {
|
||||
'errors': errors, 'total': total,
|
||||
}
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class ListMessages(command.Lister):
|
||||
_description = _('List volume failure messages')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--project',
|
||||
metavar='<project>',
|
||||
help=_('Filter results by project (name or ID) (admin only)'),
|
||||
)
|
||||
identity_common.add_project_domain_option_to_parser(parser)
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
metavar='<message-id>',
|
||||
help=_('The last message ID of the previous page'),
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
type=int,
|
||||
metavar='<limit>',
|
||||
help=_('Maximum number of messages to display'),
|
||||
default=None,
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
volume_client = self.app.client_manager.volume
|
||||
identity_client = self.app.client_manager.identity
|
||||
|
||||
if volume_client.api_version < api_versions.APIVersion('3.3'):
|
||||
msg = _(
|
||||
"--os-volume-api-version 3.3 or greater is required to "
|
||||
"support the 'volume message list' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
column_headers = (
|
||||
'ID',
|
||||
'Event ID',
|
||||
'Resource Type',
|
||||
'Resource UUID',
|
||||
'Message Level',
|
||||
'User Message',
|
||||
'Request ID',
|
||||
'Created At',
|
||||
'Guaranteed Until',
|
||||
)
|
||||
|
||||
project_id = None
|
||||
if parsed_args.project:
|
||||
project_id = identity_common.find_project(
|
||||
identity_client,
|
||||
parsed_args.project,
|
||||
parsed_args.project_domain).id
|
||||
|
||||
search_opts = {
|
||||
'project_id': project_id,
|
||||
}
|
||||
data = volume_client.messages.list(
|
||||
search_opts=search_opts,
|
||||
marker=parsed_args.marker,
|
||||
limit=parsed_args.limit)
|
||||
|
||||
return (
|
||||
column_headers,
|
||||
(utils.get_item_properties(s, column_headers) for s in data)
|
||||
)
|
||||
|
||||
|
||||
class ShowMessage(command.ShowOne):
|
||||
_description = _('Show a volume failure message')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowMessage, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'message_id',
|
||||
metavar='<message-id>',
|
||||
help=_('Message to show (ID).')
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
volume_client = self.app.client_manager.volume
|
||||
|
||||
if volume_client.api_version < api_versions.APIVersion('3.3'):
|
||||
msg = _(
|
||||
"--os-volume-api-version 3.3 or greater is required to "
|
||||
"support the 'volume message show' command"
|
||||
)
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
message = volume_client.messages.get(parsed_args.message_id)
|
||||
|
||||
return zip(*sorted(message._info.items()))
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Add ``volume message list``, ``volume message get`` and
|
||||
``volume message delete`` commands, to list, get and delete volume
|
||||
failure messages, respectively.
|
||||
|
|
@ -722,6 +722,10 @@ openstack.volume.v3 =
|
|||
|
||||
volume_host_set = openstackclient.volume.v2.volume_host:SetVolumeHost
|
||||
|
||||
volume_message_delete = openstackclient.volume.v3.volume_message:DeleteMessage
|
||||
volume_message_list = openstackclient.volume.v3.volume_message:ListMessages
|
||||
volume_message_show = openstackclient.volume.v3.volume_message:ShowMessage
|
||||
|
||||
volume_snapshot_create = openstackclient.volume.v2.volume_snapshot:CreateVolumeSnapshot
|
||||
volume_snapshot_delete = openstackclient.volume.v2.volume_snapshot:DeleteVolumeSnapshot
|
||||
volume_snapshot_list = openstackclient.volume.v2.volume_snapshot:ListVolumeSnapshot
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue