diff options
Diffstat (limited to 'openstackclient/volume')
| -rw-r--r-- | openstackclient/volume/v3/block_storage_cleanup.py | 146 | ||||
| -rw-r--r-- | openstackclient/volume/v3/block_storage_log_level.py | 147 | ||||
| -rw-r--r-- | openstackclient/volume/v3/block_storage_manage.py | 258 | ||||
| -rw-r--r-- | openstackclient/volume/v3/volume.py | 114 | ||||
| -rw-r--r-- | openstackclient/volume/v3/volume_group.py | 117 |
5 files changed, 753 insertions, 29 deletions
diff --git a/openstackclient/volume/v3/block_storage_cleanup.py b/openstackclient/volume/v3/block_storage_cleanup.py new file mode 100644 index 00000000..f99b8217 --- /dev/null +++ b/openstackclient/volume/v3/block_storage_cleanup.py @@ -0,0 +1,146 @@ +# 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.command import command +from osc_lib import exceptions + +from openstackclient.i18n import _ + + +def _format_cleanup_response(cleaning, unavailable): + column_headers = ( + 'ID', + 'Cluster Name', + 'Host', + 'Binary', + 'Status', + ) + combined_data = [] + for obj in cleaning: + details = (obj.id, obj.cluster_name, obj.host, obj.binary, 'Cleaning') + combined_data.append(details) + + for obj in unavailable: + details = (obj.id, obj.cluster_name, obj.host, obj.binary, + 'Unavailable') + combined_data.append(details) + + return (column_headers, combined_data) + + +class BlockStorageCleanup(command.Lister): + """Do block storage cleanup. + + This command requires ``--os-volume-api-version`` 3.24 or greater. + """ + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + '--cluster', + metavar='<cluster>', + help=_('Name of block storage cluster in which cleanup needs ' + 'to be performed (name only)') + ) + parser.add_argument( + "--host", + metavar="<host>", + default=None, + help=_("Host where the service resides. (name only)") + ) + parser.add_argument( + '--binary', + metavar='<binary>', + default=None, + help=_("Name of the service binary.") + ) + service_up_parser = parser.add_mutually_exclusive_group() + service_up_parser.add_argument( + '--up', + dest='is_up', + action='store_true', + default=None, + help=_( + 'Filter by up status. If this is set, services need to be up.' + ) + ) + service_up_parser.add_argument( + '--down', + dest='is_up', + action='store_false', + help=_( + 'Filter by down status. If this is set, services need to be ' + 'down.' + ) + ) + service_disabled_parser = parser.add_mutually_exclusive_group() + service_disabled_parser.add_argument( + '--disabled', + dest='disabled', + action='store_true', + default=None, + help=_('Filter by disabled status.') + ) + service_disabled_parser.add_argument( + '--enabled', + dest='disabled', + action='store_false', + help=_('Filter by enabled status.') + ) + parser.add_argument( + '--resource-id', + metavar='<resource-id>', + default=None, + help=_('UUID of a resource to cleanup.') + ) + parser.add_argument( + '--resource-type', + metavar='<Volume|Snapshot>', + choices=('Volume', 'Snapshot'), + help=_('Type of resource to cleanup.') + ) + parser.add_argument( + '--service-id', + type=int, + default=None, + help=_( + 'The service ID field from the DB, not the UUID of the ' + 'service.' + ) + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + + if volume_client.api_version < api_versions.APIVersion('3.24'): + msg = _( + "--os-volume-api-version 3.24 or greater is required to " + "support the 'block storage cleanup' command" + ) + raise exceptions.CommandError(msg) + + filters = { + 'cluster_name': parsed_args.cluster, + 'host': parsed_args.host, + 'binary': parsed_args.binary, + 'is_up': parsed_args.is_up, + 'disabled': parsed_args.disabled, + 'resource_id': parsed_args.resource_id, + 'resource_type': parsed_args.resource_type, + 'service_id': parsed_args.service_id + } + + filters = {k: v for k, v in filters.items() if v is not None} + cleaning, unavailable = volume_client.workers.clean(**filters) + return _format_cleanup_response(cleaning, unavailable) diff --git a/openstackclient/volume/v3/block_storage_log_level.py b/openstackclient/volume/v3/block_storage_log_level.py new file mode 100644 index 00000000..d5286cdd --- /dev/null +++ b/openstackclient/volume/v3/block_storage_log_level.py @@ -0,0 +1,147 @@ +# +# 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. +# + +"""Block Storage Service action 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 BlockStorageLogLevelList(command.Lister): + """List log levels of block storage service. + + Supported by --os-volume-api-version 3.32 or greater. + """ + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + "--host", + metavar="<host>", + default="", + help=_("List block storage service log level of specified host " + "(name only)") + ) + parser.add_argument( + "--service", + metavar="<service>", + default="", + choices=( + '', + '*', + 'cinder-api', + 'cinder-volume', + 'cinder-scheduler', + 'cinder-backup'), + help=_("List block storage service log level of the specified " + "service (name only)") + ) + parser.add_argument( + "--log-prefix", + metavar="<log-prefix>", + default="", + help="Prefix for the log, e.g. 'sqlalchemy'" + ) + return parser + + def take_action(self, parsed_args): + service_client = self.app.client_manager.volume + columns = [ + "Binary", + "Host", + "Prefix", + "Level", + ] + + if service_client.api_version < api_versions.APIVersion('3.32'): + msg = _( + "--os-volume-api-version 3.32 or greater is required to " + "support the 'block storage log level list' command" + ) + raise exceptions.CommandError(msg) + + data = service_client.services.get_log_levels( + binary=parsed_args.service, + server=parsed_args.host, + prefix=parsed_args.log_prefix) + + return (columns, + (utils.get_item_properties( + s, columns, + ) for s in data)) + + +class BlockStorageLogLevelSet(command.Command): + """Set log level of block storage service + + Supported by --os-volume-api-version 3.32 or greater. + """ + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + "level", + metavar="<log-level>", + choices=('INFO', 'WARNING', 'ERROR', 'DEBUG'), + type=str.upper, + help=_("Desired log level.") + ) + parser.add_argument( + "--host", + metavar="<host>", + default="", + help=_("Set block storage service log level of specified host " + "(name only)") + ) + parser.add_argument( + "--service", + metavar="<service>", + default="", + choices=( + '', + '*', + 'cinder-api', + 'cinder-volume', + 'cinder-scheduler', + 'cinder-backup'), + help=_("Set block storage service log level of specified service " + "(name only)") + ) + parser.add_argument( + "--log-prefix", + metavar="<log-prefix>", + default="", + help="Prefix for the log, e.g. 'sqlalchemy'" + ) + return parser + + def take_action(self, parsed_args): + service_client = self.app.client_manager.volume + + if service_client.api_version < api_versions.APIVersion('3.32'): + msg = _( + "--os-volume-api-version 3.32 or greater is required to " + "support the 'block storage log level set' command" + ) + raise exceptions.CommandError(msg) + + service_client.services.set_log_levels( + level=parsed_args.level, + binary=parsed_args.service, + server=parsed_args.host, + prefix=parsed_args.log_prefix) diff --git a/openstackclient/volume/v3/block_storage_manage.py b/openstackclient/volume/v3/block_storage_manage.py new file mode 100644 index 00000000..9015f44d --- /dev/null +++ b/openstackclient/volume/v3/block_storage_manage.py @@ -0,0 +1,258 @@ +# 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. +# + +"""Block Storage Volume/Snapshot Management implementations""" + +from cinderclient import api_versions +from osc_lib.command import command +from osc_lib import exceptions +from osc_lib import utils +from oslo_utils import strutils + +from openstackclient.i18n import _ + + +SORT_MANAGEABLE_KEY_VALUES = ('size', 'reference') + + +class BlockStorageManageVolumes(command.Lister): + """List manageable volumes. + + Supported by --os-volume-api-version 3.8 or greater. + """ + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + host_group = parser.add_mutually_exclusive_group() + host_group.add_argument( + "host", + metavar="<host>", + nargs='?', + help=_('Cinder host on which to list manageable volumes. ' + 'Takes the form: host@backend-name#pool') + ) + host_group.add_argument( + "--cluster", + metavar="<cluster>", + help=_('Cinder cluster on which to list manageable volumes. ' + 'Takes the form: cluster@backend-name#pool. ' + '(supported by --os-volume-api-version 3.17 or later)') + ) + parser.add_argument( + '--detailed', + metavar='<detailed>', + default=True, + help=_('Returns detailed information (Default=True).') + ) + parser.add_argument( + '--marker', + metavar='<marker>', + default=None, + help=_('Begin returning volumes that appear later in the volume ' + 'list than that represented by this reference. This ' + 'reference should be json like. Default=None.') + ) + parser.add_argument( + '--limit', + metavar='<limit>', + default=None, + help=_('Maximum number of volumes to return. Default=None.') + ) + parser.add_argument( + '--offset', + metavar='<offset>', + default=None, + help=_('Number of volumes to skip after marker. Default=None.') + ) + parser.add_argument( + '--sort', + metavar='<key>[:<direction>]', + default=None, + help=(_('Comma-separated list of sort keys and directions in the ' + 'form of <key>[:<asc|desc>]. ' + 'Valid keys: %s. ' + 'Default=None.') % ', '.join(SORT_MANAGEABLE_KEY_VALUES)) + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + + if parsed_args.host is None and parsed_args.cluster is None: + msg = _( + "Either <host> or '--cluster <cluster>' needs to be provided " + "to run the 'block storage volume manageable list' command" + ) + raise exceptions.CommandError(msg) + + if volume_client.api_version < api_versions.APIVersion('3.8'): + msg = _( + "--os-volume-api-version 3.8 or greater is required to " + "support the 'block storage volume manageable list' command" + ) + raise exceptions.CommandError(msg) + + if parsed_args.cluster: + if volume_client.api_version < api_versions.APIVersion('3.17'): + msg = _( + "--os-volume-api-version 3.17 or greater is required to " + "support the '--cluster' option" + ) + raise exceptions.CommandError(msg) + + detailed = strutils.bool_from_string(parsed_args.detailed) + cluster = getattr(parsed_args, 'cluster', None) + + columns = [ + 'reference', + 'size', + 'safe_to_manage', + ] + if detailed: + columns.extend([ + 'reason_not_safe', + 'cinder_id', + 'extra_info', + ]) + + data = volume_client.volumes.list_manageable( + host=parsed_args.host, + detailed=detailed, + marker=parsed_args.marker, + limit=parsed_args.limit, + offset=parsed_args.offset, + sort=parsed_args.sort, + cluster=cluster) + + return (columns, + (utils.get_item_properties( + s, columns, + ) for s in data)) + + +class BlockStorageManageSnapshots(command.Lister): + """List manageable snapshots. + + Supported by --os-volume-api-version 3.8 or greater. + """ + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + host_group = parser.add_mutually_exclusive_group() + host_group.add_argument( + "host", + metavar="<host>", + nargs='?', + help=_('Cinder host on which to list manageable snapshots. ' + 'Takes the form: host@backend-name#pool') + ) + host_group.add_argument( + "--cluster", + metavar="<cluster>", + help=_('Cinder cluster on which to list manageable snapshots. ' + 'Takes the form: cluster@backend-name#pool. ' + '(supported by --os-volume-api-version 3.17 or later)') + ) + parser.add_argument( + '--detailed', + metavar='<detailed>', + default=True, + help=_('Returns detailed information (Default=True).') + ) + parser.add_argument( + '--marker', + metavar='<marker>', + default=None, + help=_('Begin returning snapshots that appear later in the ' + 'snapshot list than that represented by this reference. ' + 'This reference should be json like. Default=None.') + ) + parser.add_argument( + '--limit', + metavar='<limit>', + default=None, + help=_('Maximum number of snapshots to return. Default=None.') + ) + parser.add_argument( + '--offset', + metavar='<offset>', + default=None, + help=_('Number of snapshots to skip after marker. Default=None.') + ) + parser.add_argument( + '--sort', + metavar='<key>[:<direction>]', + default=None, + help=(_('Comma-separated list of sort keys and directions in the ' + 'form of <key>[:<asc|desc>]. ' + 'Valid keys: %s. ' + 'Default=None.') % ', '.join(SORT_MANAGEABLE_KEY_VALUES)) + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + + if parsed_args.host is None and parsed_args.cluster is None: + msg = _( + "Either <host> or '--cluster <cluster>' needs to be provided " + "to run the 'block storage volume snapshot manageable list' " + "command" + ) + raise exceptions.CommandError(msg) + + if volume_client.api_version < api_versions.APIVersion('3.8'): + msg = _( + "--os-volume-api-version 3.8 or greater is required to " + "support the 'block storage volume snapshot manageable list' " + "command" + ) + raise exceptions.CommandError(msg) + + if parsed_args.cluster: + if volume_client.api_version < api_versions.APIVersion('3.17'): + msg = _( + "--os-volume-api-version 3.17 or greater is required to " + "support the '--cluster' option" + ) + raise exceptions.CommandError(msg) + + detailed = strutils.bool_from_string(parsed_args.detailed) + cluster = getattr(parsed_args, 'cluster', None) + + columns = [ + 'reference', + 'size', + 'safe_to_manage', + 'source_reference', + ] + if detailed: + columns.extend([ + 'reason_not_safe', + 'cinder_id', + 'extra_info', + ]) + + data = volume_client.volume_snapshots.list_manageable( + host=parsed_args.host, + detailed=detailed, + marker=parsed_args.marker, + limit=parsed_args.limit, + offset=parsed_args.offset, + sort=parsed_args.sort, + cluster=cluster) + + return (columns, + (utils.get_item_properties( + s, columns, + ) for s in data)) diff --git a/openstackclient/volume/v3/volume.py b/openstackclient/volume/v3/volume.py new file mode 100644 index 00000000..4b159688 --- /dev/null +++ b/openstackclient/volume/v3/volume.py @@ -0,0 +1,114 @@ +# +# 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 Volume action implementations""" + +import logging + +from cinderclient import api_versions +from osc_lib.cli import format_columns +from osc_lib.command import command +from osc_lib import exceptions +from osc_lib import utils + +from openstackclient.i18n import _ + + +LOG = logging.getLogger(__name__) + + +class VolumeSummary(command.ShowOne): + _description = _("Show a summary of all volumes in this deployment.") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + '--all-projects', + action='store_true', + default=False, + help=_('Include all projects (admin only)'), + ) + return parser + + def take_action(self, parsed_args): + + volume_client = self.app.client_manager.volume + + if volume_client.api_version < api_versions.APIVersion('3.12'): + msg = _( + "--os-volume-api-version 3.12 or greater is required to " + "support the 'volume summary' command" + ) + raise exceptions.CommandError(msg) + + columns = [ + 'total_count', + 'total_size', + ] + column_headers = [ + 'Total Count', + 'Total Size', + ] + if volume_client.api_version.matches('3.36'): + columns.append('metadata') + column_headers.append('Metadata') + + # set value of 'all_tenants' when using project option + all_projects = parsed_args.all_projects + + vol_summary = volume_client.volumes.summary( + all_tenants=all_projects, + ) + + return ( + column_headers, + utils.get_dict_properties( + vol_summary['volume-summary'], + columns, + formatters={'metadata': format_columns.DictColumn}, + ), + ) + + +class VolumeRevertToSnapshot(command.Command): + _description = _("Revert a volume to a snapshot.") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + 'snapshot', + metavar="<snapshot>", + help=_('Name or ID of the snapshot to restore. The snapshot must ' + 'be the most recent one known to cinder.'), + ) + return parser + + def take_action(self, parsed_args): + + volume_client = self.app.client_manager.volume + + if volume_client.api_version < api_versions.APIVersion('3.40'): + msg = _( + "--os-volume-api-version 3.40 or greater is required to " + "support the 'volume revert snapshot' command" + ) + raise exceptions.CommandError(msg) + + snapshot = utils.find_resource( + volume_client.volume_snapshots, parsed_args.snapshot) + volume = utils.find_resource( + volume_client.volumes, snapshot.volume_id) + + volume_client.volumes.revert_to_snapshot( + volume=volume, snapshot=snapshot) diff --git a/openstackclient/volume/v3/volume_group.py b/openstackclient/volume/v3/volume_group.py index db4e9a94..69b18ceb 100644 --- a/openstackclient/volume/v3/volume_group.py +++ b/openstackclient/volume/v3/volume_group.py @@ -82,15 +82,17 @@ class CreateVolumeGroup(command.ShowOne): def get_parser(self, prog_name): parser = super().get_parser(prog_name) - parser.add_argument( + source_parser = parser.add_mutually_exclusive_group() + source_parser.add_argument( 'volume_group_type', metavar='<volume_group_type>', + nargs='?', help=_('Name or ID of volume group type to use.'), ) parser.add_argument( 'volume_types', metavar='<volume_type>', - nargs='+', + nargs='*', default=[], help=_('Name or ID of volume type(s) to use.'), ) @@ -107,44 +109,101 @@ class CreateVolumeGroup(command.ShowOne): parser.add_argument( '--availability-zone', metavar='<availability-zone>', - help=_('Availability zone for volume group.'), + help=_('Availability zone for volume group. ' + '(not available if creating group from source)'), + ) + source_parser.add_argument( + '--source-group', + metavar='<source-group>', + help=_('Existing volume group (name or ID) ' + '(supported by --os-volume-api-version 3.14 or later)'), + ) + source_parser.add_argument( + '--group-snapshot', + metavar='<group-snapshot>', + help=_('Existing group snapshot (name or ID) ' + '(supported by --os-volume-api-version 3.14 or later)'), ) return parser def take_action(self, parsed_args): volume_client = self.app.client_manager.volume - if volume_client.api_version < api_versions.APIVersion('3.13'): - msg = _( - "--os-volume-api-version 3.13 or greater is required to " - "support the 'volume group create' command" - ) - raise exceptions.CommandError(msg) - - volume_group_type = utils.find_resource( - volume_client.group_types, - parsed_args.volume_group_type, - ) - - volume_types = [] - for volume_type in parsed_args.volume_types: - volume_types.append( - utils.find_resource( - volume_client.volume_types, - volume_type, + if parsed_args.volume_group_type: + if volume_client.api_version < api_versions.APIVersion('3.13'): + msg = _( + "--os-volume-api-version 3.13 or greater is required to " + "support the 'volume group create' command" ) + raise exceptions.CommandError(msg) + if not parsed_args.volume_types: + msg = _( + "<volume_types> is a required argument when creating a " + "group from group type." + ) + raise exceptions.CommandError(msg) + + volume_group_type = utils.find_resource( + volume_client.group_types, + parsed_args.volume_group_type, ) + volume_types = [] + for volume_type in parsed_args.volume_types: + volume_types.append( + utils.find_resource( + volume_client.volume_types, + volume_type, + ) + ) - group = volume_client.groups.create( - volume_group_type.id, - ','.join(x.id for x in volume_types), - parsed_args.name, - parsed_args.description, - availability_zone=parsed_args.availability_zone) + group = volume_client.groups.create( + volume_group_type.id, + ','.join(x.id for x in volume_types), + parsed_args.name, + parsed_args.description, + availability_zone=parsed_args.availability_zone) - group = volume_client.groups.get(group.id) + group = volume_client.groups.get(group.id) + return _format_group(group) - return _format_group(group) + else: + if volume_client.api_version < api_versions.APIVersion('3.14'): + msg = _( + "--os-volume-api-version 3.14 or greater is required to " + "support the 'volume group create " + "[--source-group|--group-snapshot]' command" + ) + raise exceptions.CommandError(msg) + if (parsed_args.source_group is None and + parsed_args.group_snapshot is None): + msg = _( + "Either --source-group <source_group> or " + "'--group-snapshot <group_snapshot>' needs to be " + "provided to run the 'volume group create " + "[--source-group|--group-snapshot]' command" + ) + raise exceptions.CommandError(msg) + if parsed_args.availability_zone: + msg = _("'--availability-zone' option will not work " + "if creating group from source.") + LOG.warning(msg) + + source_group = None + if parsed_args.source_group: + source_group = utils.find_resource(volume_client.groups, + parsed_args.source_group) + group_snapshot = None + if parsed_args.group_snapshot: + group_snapshot = utils.find_resource( + volume_client.group_snapshots, + parsed_args.group_snapshot) + group = volume_client.groups.create_from_src( + group_snapshot.id if group_snapshot else None, + source_group.id if source_group else None, + parsed_args.name, + parsed_args.description) + group = volume_client.groups.get(group.id) + return _format_group(group) class DeleteVolumeGroup(command.Command): |
