Files
python-manilaclient/manilaclient/osc/v2/share_backups.py
Stephen Finucane 3e3b385c8c Re-enable E501 errors
Change-Id: Id6ca5075bd11765f00b62b44f91635ef68205175
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2025-10-31 14:06:12 +00:00

500 lines
15 KiB
Python

# Copyright 2023 Cloudification GmbH.
# All Rights Reserved.
#
# 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.
import logging
from osc_lib.cli import parseractions
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils as osc_utils
from manilaclient import api_versions
from manilaclient.common._i18n import _
from manilaclient.common import constants
from manilaclient.osc import utils
LOG = logging.getLogger(__name__)
class CreateShareBackup(command.ShowOne):
"""Create a share backup."""
_description = _("Create a backup of the given share")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"share",
metavar="<share>",
help=_("Name or ID of the share to backup."),
)
parser.add_argument(
'--name',
metavar='<name>',
default=None,
help=_('Optional share backup name. (Default=None).'),
)
parser.add_argument(
'--description',
metavar='<description>',
default=None,
help=_('Optional share backup description. (Default=None).'),
)
parser.add_argument(
"--backup-options",
metavar="<key=value>",
default={},
action=parseractions.KeyValueAction,
help=_(
"Backup driver option key=value pairs (Optional, "
"Default=None)."
),
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
share = osc_utils.find_resource(share_client.shares, parsed_args.share)
body = {}
if parsed_args.backup_options:
body['backup_options'] = utils.extract_key_value_options(
parsed_args.backup_options
)
if parsed_args.description:
body['description'] = parsed_args.description
if parsed_args.name:
body['name'] = parsed_args.name
share_backup = share_client.share_backups.create(share, **body)
share_backup._info.pop('links', None)
return self.dict2columns(share_backup._info)
class DeleteShareBackup(command.Command):
"""Delete one or more share backups."""
_description = _("Delete one or more share backups")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"backup",
metavar="<backup>",
nargs="+",
help=_("Name or ID of the backup(s) to delete"),
)
parser.add_argument(
"--wait",
action='store_true',
default=False,
help=_("Wait for share backup deletion"),
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
result = 0
for backup in parsed_args.backup:
try:
share_backup_obj = osc_utils.find_resource(
share_client.share_backups, backup
)
share_client.share_backups.delete(share_backup_obj)
if parsed_args.wait:
if not osc_utils.wait_for_delete(
manager=share_client.share_backups,
res_id=share_backup_obj.id,
):
result += 1
except Exception as e:
result += 1
LOG.error(
_(
"Failed to delete a share backup with "
"name or ID '%(backup)s': %(e)s"
),
{'backup': backup, 'e': e},
)
if result > 0:
total = len(parsed_args.backup)
msg = _("%(result)s of %(total)s backups failed to delete.") % {
'result': result,
'total': total,
}
raise exceptions.CommandError(msg)
class ListShareBackup(command.Lister):
"""List share backups."""
_description = _("List share backups")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"--share",
metavar="<share>",
default=None,
help=_("Name or ID of the share to list backups for."),
)
parser.add_argument(
"--name",
metavar="<name>",
default=None,
help=_("Filter results by name. Default=None."),
)
parser.add_argument(
'--description',
metavar="<description>",
default=None,
help=_("Filter results by description. Default=None."),
)
parser.add_argument(
"--name~",
metavar="<name~>",
default=None,
help=_("Filter results matching a share backup name pattern. "),
)
parser.add_argument(
'--description~',
metavar="<description~>",
default=None,
help=_("Filter results matching a share backup description "),
)
parser.add_argument(
'--status',
metavar="<status>",
default=None,
help=_('Filter results by status. Default=None.'),
)
parser.add_argument(
"--limit",
metavar="<num-backups>",
type=int,
default=None,
action=parseractions.NonNegativeAction,
help=_("Limit the number of backups returned. Default=None."),
)
parser.add_argument(
'--offset',
metavar="<offset>",
default=None,
help='Start position of backup records listing.',
)
parser.add_argument(
'--sort-key',
'--sort_key',
metavar='<sort_key>',
type=str,
default=None,
help=(
f'Key to be sorted, available keys are '
f'{constants.BACKUP_SORT_KEY_VALUES}. Default=None.'
),
)
parser.add_argument(
'--sort-dir',
'--sort_dir',
metavar='<sort_dir>',
type=str,
default=None,
help=(
f'Sort direction, available values are '
f'{constants.SORT_DIR_VALUES}. OPTIONAL: Default=None.'
),
)
parser.add_argument(
'--detail',
dest='detail',
metavar='<0|1>',
nargs='?',
type=int,
const=1,
default=0,
help="Show detailed information about share backups.",
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
share_id = None
if parsed_args.share:
share_id = osc_utils.find_resource(
share_client.shares, parsed_args.share
).id
columns = ['ID', 'Name', 'Share ID', 'Status']
if parsed_args.detail:
columns.extend(
[
'Description',
'Size',
'Created At',
'Updated At',
'Availability Zone',
'Progress',
'Restore Progress',
'Host',
'Topic',
]
)
search_opts = {
'limit': parsed_args.limit,
'offset': parsed_args.offset,
'name': parsed_args.name,
'description': parsed_args.description,
'status': parsed_args.status,
'share_id': share_id,
}
search_opts['name~'] = getattr(parsed_args, 'name~')
search_opts['description~'] = getattr(parsed_args, 'description~')
backups = share_client.share_backups.list(
detailed=parsed_args.detail,
search_opts=search_opts,
sort_key=parsed_args.sort_key,
sort_dir=parsed_args.sort_dir,
)
return (
columns,
(osc_utils.get_item_properties(b, columns) for b in backups),
)
class ShowShareBackup(command.ShowOne):
"""Show share backup."""
_description = _("Show details of a backup")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"backup", metavar="<backup>", help=_("ID of the share backup. ")
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
backup = osc_utils.find_resource(
share_client.share_backups, parsed_args.backup
)
backup._info.pop('links', None)
return self.dict2columns(backup._info)
class RestoreShareBackup(command.Command):
"""Restore share backup to share"""
_description = _("Attempt to restore share backup")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"backup", metavar="<backup>", help=_('ID of backup to restore.')
)
parser.add_argument(
"--target-share",
metavar="<target-share>",
default=None,
help=_(
'share to restore backup to. Source share if none supplied'
),
)
parser.add_argument(
'--wait',
action='store_true',
default=False,
help=_('Wait for restore conclusion'),
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
kwargs = {}
share_backup = osc_utils.find_resource(
share_client.share_backups, parsed_args.backup
)
target_share_id = None
if parsed_args.target_share is not None:
if share_client.api_version < api_versions.APIVersion('2.91'):
raise exceptions.CommandError(
'performing targeted restores is only available '
'for API microversion >= 2.91'
)
else:
target_share_id = osc_utils.find_resource(
share_client.shares, parsed_args.target_share
).id
kwargs['target_share_id'] = target_share_id
share_client.share_backups.restore(share_backup.id, **kwargs)
if parsed_args.wait:
if not osc_utils.wait_for_status(
status_f=share_client.shares.get,
res_id=(target_share_id or share_backup.share_id),
success_status=['available'],
error_status=['error', 'backup_restoring_error'],
):
LOG.error(_("ERROR: share is in error state."))
class SetShareBackup(command.Command):
"""Set share backup properties."""
_description = _("Set share backup properties")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"backup",
metavar="<backup>",
help=_('Name or ID of the backup to set a property for'),
)
parser.add_argument(
"--name",
metavar="<name>",
default=None,
help=_("Set a name to the backup."),
)
parser.add_argument(
"--description",
metavar="<description>",
default=None,
help=_("Set a description to the backup."),
)
parser.add_argument(
"--status",
metavar="<status>",
choices=[
'available',
'error',
'creating',
'deleting',
'restoring',
],
help=_(
"Assign a status to the backup(Admin only). "
"Options include : available, error, creating, "
"deleting, restoring."
),
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
result = 0
share_backup = osc_utils.find_resource(
share_client.share_backups, parsed_args.backup
)
kwargs = {}
if parsed_args.name is not None:
kwargs['name'] = parsed_args.name
if parsed_args.description is not None:
kwargs['description'] = parsed_args.description
try:
share_client.share_backups.update(share_backup, **kwargs)
except Exception as e:
result += 1
LOG.error(
_(
"Failed to set share backup properties "
"'%(properties)s': %(exception)s"
),
{'properties': kwargs, 'exception': e},
)
if parsed_args.status:
try:
share_client.share_backups.reset_status(
share_backup, parsed_args.status
)
except Exception as e:
result += 1
LOG.error(
_("Failed to update backup status to '%(status)s': %(e)s"),
{'status': parsed_args.status, 'e': e},
)
if result > 0:
raise exceptions.CommandError(
_("One or more of the set operations failed")
)
class UnsetShareBackup(command.Command):
"""Unset share backup properties."""
_description = _("Unset share backup properties")
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument(
"backup",
metavar="<backup>",
help=_('Name or ID of the backup to unset a property for'),
)
parser.add_argument(
"--name",
action='store_true',
help=_("Unset a name to the backup."),
)
parser.add_argument(
"--description",
action='store_true',
help=_("Unset a description to the backup."),
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
share_backup = osc_utils.find_resource(
share_client.share_backups, parsed_args.backup
)
kwargs = {}
if parsed_args.name:
kwargs['name'] = None
if parsed_args.description:
kwargs['description'] = None
if not kwargs:
msg = "Either name or description must be provided."
raise exceptions.CommandError(msg)
try:
share_client.share_backups.update(share_backup, **kwargs)
except Exception as e:
LOG.error(
_(
"Failed to unset share backup properties "
"'%(properties)s': %(exception)s"
),
{'properties': kwargs, 'exception': e},
)