Merge "mypy: cmd/manage.py"
This commit is contained in:
commit
c210c87495
@ -50,6 +50,8 @@
|
|||||||
|
|
||||||
"""CLI interface for cinder management."""
|
"""CLI interface for cinder management."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import collections.abc as collections_abc
|
import collections.abc as collections_abc
|
||||||
import errno
|
import errno
|
||||||
@ -60,6 +62,8 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import typing
|
||||||
|
from typing import Any, Callable, Optional, Tuple, Union # noqa: H301
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_db import exception as db_exc
|
from oslo_db import exception as db_exc
|
||||||
@ -101,6 +105,7 @@ OVO_VERSION = ovo_base.OBJ_VERSIONS.get_current()
|
|||||||
|
|
||||||
|
|
||||||
# Decorators for actions
|
# Decorators for actions
|
||||||
|
@typing.no_type_check
|
||||||
def args(*args, **kwargs):
|
def args(*args, **kwargs):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
if not args[0].startswith('-') and '-' in args[0]:
|
if not args[0].startswith('-') and '-' in args[0]:
|
||||||
@ -118,7 +123,7 @@ class HostCommands(object):
|
|||||||
|
|
||||||
@args('zone', nargs='?', default=None,
|
@args('zone', nargs='?', default=None,
|
||||||
help='Availability Zone (default: %(default)s)')
|
help='Availability Zone (default: %(default)s)')
|
||||||
def list(self, zone=None):
|
def list(self, zone: Optional[str] = None) -> None:
|
||||||
"""Show a list of all physical hosts.
|
"""Show a list of all physical hosts.
|
||||||
|
|
||||||
Can be filtered by zone.
|
Can be filtered by zone.
|
||||||
@ -129,7 +134,7 @@ class HostCommands(object):
|
|||||||
services = objects.ServiceList.get_all(ctxt)
|
services = objects.ServiceList.get_all(ctxt)
|
||||||
if zone:
|
if zone:
|
||||||
services = [s for s in services if s.availability_zone == zone]
|
services = [s for s in services if s.availability_zone == zone]
|
||||||
hosts = []
|
hosts: list[dict[str, Any]] = []
|
||||||
for srv in services:
|
for srv in services:
|
||||||
if not [h for h in hosts if h['host'] == srv['host']]:
|
if not [h for h in hosts if h['host'] == srv['host']]:
|
||||||
hosts.append(srv)
|
hosts.append(srv)
|
||||||
@ -152,7 +157,8 @@ class DbCommands(object):
|
|||||||
# preceed any element of the "online_migrations" tuple, like this:
|
# preceed any element of the "online_migrations" tuple, like this:
|
||||||
# # Added in Queens remove in Rocky
|
# # Added in Queens remove in Rocky
|
||||||
# db.service_uuids_online_data_migration,
|
# db.service_uuids_online_data_migration,
|
||||||
online_migrations = (
|
online_migrations: Tuple[Callable[[context.RequestContext, int],
|
||||||
|
Tuple[int, int]], ...] = (
|
||||||
# TODO: (Z Release) Remove next line and this comment
|
# TODO: (Z Release) Remove next line and this comment
|
||||||
# TODO: (Y Release) Uncomment next line and remove this comment
|
# TODO: (Y Release) Uncomment next line and remove this comment
|
||||||
# db.remove_temporary_admin_metadata_data_migration,
|
# db.remove_temporary_admin_metadata_data_migration,
|
||||||
@ -172,7 +178,9 @@ class DbCommands(object):
|
|||||||
help='Update RPC and Objects versions when doing offline upgrades, '
|
help='Update RPC and Objects versions when doing offline upgrades, '
|
||||||
'with this we no longer need to restart the services twice '
|
'with this we no longer need to restart the services twice '
|
||||||
'after the upgrade to prevent ServiceTooOld exceptions.')
|
'after the upgrade to prevent ServiceTooOld exceptions.')
|
||||||
def sync(self, version=None, bump_versions=False):
|
def sync(self,
|
||||||
|
version: Optional[int] = None,
|
||||||
|
bump_versions: bool = False) -> None:
|
||||||
"""Sync the database up to the most recent version."""
|
"""Sync the database up to the most recent version."""
|
||||||
if version is not None and version > db.MAX_INT:
|
if version is not None and version > db.MAX_INT:
|
||||||
print(_('Version should be less than or equal to '
|
print(_('Version should be less than or equal to '
|
||||||
@ -199,13 +207,13 @@ class DbCommands(object):
|
|||||||
print(_('Error during service version bump: %s') % ex)
|
print(_('Error during service version bump: %s') % ex)
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
def version(self):
|
def version(self) -> None:
|
||||||
"""Print the current database version."""
|
"""Print the current database version."""
|
||||||
print(db_migration.db_version())
|
print(db_migration.db_version())
|
||||||
|
|
||||||
@args('age_in_days', type=int,
|
@args('age_in_days', type=int,
|
||||||
help='Purge deleted rows older than age in days')
|
help='Purge deleted rows older than age in days')
|
||||||
def purge(self, age_in_days):
|
def purge(self, age_in_days: int) -> None:
|
||||||
"""Purge deleted rows older than a given age from cinder tables."""
|
"""Purge deleted rows older than a given age from cinder tables."""
|
||||||
age_in_days = int(age_in_days)
|
age_in_days = int(age_in_days)
|
||||||
if age_in_days < 0:
|
if age_in_days < 0:
|
||||||
@ -223,7 +231,9 @@ class DbCommands(object):
|
|||||||
"logs for more details."))
|
"logs for more details."))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def _run_migration(self, ctxt, max_count):
|
def _run_migration(self,
|
||||||
|
ctxt: context.RequestContext,
|
||||||
|
max_count: int) -> Tuple[dict, bool]:
|
||||||
ran = 0
|
ran = 0
|
||||||
exceptions = False
|
exceptions = False
|
||||||
migrations = {}
|
migrations = {}
|
||||||
@ -254,7 +264,7 @@ class DbCommands(object):
|
|||||||
|
|
||||||
@args('--max_count', metavar='<number>', dest='max_count', type=int,
|
@args('--max_count', metavar='<number>', dest='max_count', type=int,
|
||||||
help='Maximum number of objects to consider.')
|
help='Maximum number of objects to consider.')
|
||||||
def online_data_migrations(self, max_count=None):
|
def online_data_migrations(self, max_count: Optional[int] = None) -> None:
|
||||||
"""Perform online data migrations for the release in batches."""
|
"""Perform online data migrations for the release in batches."""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
if max_count is not None:
|
if max_count is not None:
|
||||||
@ -269,7 +279,7 @@ class DbCommands(object):
|
|||||||
|
|
||||||
ran = None
|
ran = None
|
||||||
exceptions = False
|
exceptions = False
|
||||||
migration_info = {}
|
migration_info: dict[str, Any] = {}
|
||||||
while ran is None or ran != 0:
|
while ran is None or ran != 0:
|
||||||
migrations, exceptions = self._run_migration(ctxt, max_count)
|
migrations, exceptions = self._run_migration(ctxt, max_count)
|
||||||
ran = 0
|
ran = 0
|
||||||
@ -311,8 +321,10 @@ class DbCommands(object):
|
|||||||
help='Change the active backend ID (default: %(default)s).')
|
help='Change the active backend ID (default: %(default)s).')
|
||||||
@args('--backend-host', required=True,
|
@args('--backend-host', required=True,
|
||||||
help='The backend host name.')
|
help='The backend host name.')
|
||||||
def reset_active_backend(self, enable_replication, active_backend_id,
|
def reset_active_backend(self,
|
||||||
backend_host):
|
enable_replication: bool,
|
||||||
|
active_backend_id: Optional[str],
|
||||||
|
backend_host: str) -> None:
|
||||||
"""Reset the active backend for a host."""
|
"""Reset the active backend for a host."""
|
||||||
|
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
@ -336,7 +348,7 @@ class QuotaCommands(object):
|
|||||||
@args('--project-id', default=None,
|
@args('--project-id', default=None,
|
||||||
help=('The ID of the project where we want to sync the quotas '
|
help=('The ID of the project where we want to sync the quotas '
|
||||||
'(defaults to all projects).'))
|
'(defaults to all projects).'))
|
||||||
def check(self, project_id):
|
def check(self, project_id: Optional[str]) -> None:
|
||||||
"""Check if quotas and reservations are correct
|
"""Check if quotas and reservations are correct
|
||||||
|
|
||||||
This action checks quotas and reservations, for a specific project or
|
This action checks quotas and reservations, for a specific project or
|
||||||
@ -356,7 +368,7 @@ class QuotaCommands(object):
|
|||||||
@args('--project-id', default=None,
|
@args('--project-id', default=None,
|
||||||
help=('The ID of the project where we want to sync the quotas '
|
help=('The ID of the project where we want to sync the quotas '
|
||||||
'(defaults to all projects).'))
|
'(defaults to all projects).'))
|
||||||
def sync(self, project_id):
|
def sync(self, project_id: Optional[str]) -> None:
|
||||||
"""Fix quotas and reservations
|
"""Fix quotas and reservations
|
||||||
|
|
||||||
This action refreshes existing quota usage and reservation count for a
|
This action refreshes existing quota usage and reservation count for a
|
||||||
@ -373,7 +385,9 @@ class QuotaCommands(object):
|
|||||||
self._check_sync(project_id, do_fix=True)
|
self._check_sync(project_id, do_fix=True)
|
||||||
|
|
||||||
@db_api.main_context_manager.reader
|
@db_api.main_context_manager.reader
|
||||||
def _get_quota_projects(self, context, project_id):
|
def _get_quota_projects(self,
|
||||||
|
context: context.RequestContext,
|
||||||
|
project_id: Optional[str]) -> list[str]:
|
||||||
"""Get project ids that have quota_usage entries."""
|
"""Get project ids that have quota_usage entries."""
|
||||||
if project_id:
|
if project_id:
|
||||||
model = models.QuotaUsage
|
model = models.QuotaUsage
|
||||||
@ -402,7 +416,10 @@ class QuotaCommands(object):
|
|||||||
project_ids = [row.project_id for row in projects]
|
project_ids = [row.project_id for row in projects]
|
||||||
return project_ids
|
return project_ids
|
||||||
|
|
||||||
def _get_usages(self, context, resources, project_id):
|
def _get_usages(self,
|
||||||
|
ctxt: context.RequestContext,
|
||||||
|
resources,
|
||||||
|
project_id: str) -> list:
|
||||||
"""Get data necessary to check out of sync quota usage.
|
"""Get data necessary to check out of sync quota usage.
|
||||||
|
|
||||||
Returns a list QuotaUsage instances for the specific project
|
Returns a list QuotaUsage instances for the specific project
|
||||||
@ -414,7 +431,10 @@ class QuotaCommands(object):
|
|||||||
).filter_by(project_id=project_id).with_for_update().all()
|
).filter_by(project_id=project_id).with_for_update().all()
|
||||||
return usages
|
return usages
|
||||||
|
|
||||||
def _get_reservations(self, context, project_id, usage_id):
|
def _get_reservations(self,
|
||||||
|
ctxt: context.RequestContext,
|
||||||
|
project_id: str,
|
||||||
|
usage_id: str) -> list:
|
||||||
"""Get reservations for a given project and usage id."""
|
"""Get reservations for a given project and usage id."""
|
||||||
reservations = (
|
reservations = (
|
||||||
db_api.model_query(
|
db_api.model_query(
|
||||||
@ -428,7 +448,10 @@ class QuotaCommands(object):
|
|||||||
)
|
)
|
||||||
return reservations
|
return reservations
|
||||||
|
|
||||||
def _check_duplicates(self, context, usages, do_fix):
|
def _check_duplicates(self,
|
||||||
|
context: context.RequestContext,
|
||||||
|
usages,
|
||||||
|
do_fix: bool) -> tuple[list, bool]:
|
||||||
"""Look for duplicated quota used entries (bug#1484343)
|
"""Look for duplicated quota used entries (bug#1484343)
|
||||||
|
|
||||||
If we have duplicates and we are fixing them, then we reassign the
|
If we have duplicates and we are fixing them, then we reassign the
|
||||||
@ -470,7 +493,7 @@ class QuotaCommands(object):
|
|||||||
result.append(keep_usage)
|
result.append(keep_usage)
|
||||||
return result, duplicates_found
|
return result, duplicates_found
|
||||||
|
|
||||||
def _check_sync(self, project_id, do_fix):
|
def _check_sync(self, project_id: Optional[str], do_fix: bool) -> bool:
|
||||||
"""Check the quotas and reservations optionally fixing them."""
|
"""Check the quotas and reservations optionally fixing them."""
|
||||||
|
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
@ -496,7 +519,11 @@ class QuotaCommands(object):
|
|||||||
return discrepancy
|
return discrepancy
|
||||||
|
|
||||||
@db_api.main_context_manager.reader
|
@db_api.main_context_manager.reader
|
||||||
def _check_project_sync(self, context, project, do_fix, resources):
|
def _check_project_sync(self,
|
||||||
|
context: context.RequestContext,
|
||||||
|
project: str,
|
||||||
|
do_fix: bool,
|
||||||
|
resources) -> bool:
|
||||||
print('Processing quota usage for project %s' % project)
|
print('Processing quota usage for project %s' % project)
|
||||||
|
|
||||||
discrepancy = False
|
discrepancy = False
|
||||||
@ -579,7 +606,7 @@ class VolumeCommands(object):
|
|||||||
|
|
||||||
@args('volume_id',
|
@args('volume_id',
|
||||||
help='Volume ID to be deleted')
|
help='Volume ID to be deleted')
|
||||||
def delete(self, volume_id):
|
def delete(self, volume_id: str) -> None:
|
||||||
"""Delete a volume, bypassing the check that it must be available."""
|
"""Delete a volume, bypassing the check that it must be available."""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
volume = objects.Volume.get_by_id(ctxt, volume_id)
|
volume = objects.Volume.get_by_id(ctxt, volume_id)
|
||||||
@ -604,7 +631,7 @@ class VolumeCommands(object):
|
|||||||
'the format host@backend#pool')
|
'the format host@backend#pool')
|
||||||
@args('--newhost', required=True, help='New volume host name in the '
|
@args('--newhost', required=True, help='New volume host name in the '
|
||||||
'format host@backend#pool')
|
'format host@backend#pool')
|
||||||
def update_host(self, currenthost, newhost):
|
def update_host(self, currenthost: str, newhost: str) -> None:
|
||||||
"""Modify the host name associated with a volume.
|
"""Modify the host name associated with a volume.
|
||||||
|
|
||||||
Particularly to recover from cases where one has moved
|
Particularly to recover from cases where one has moved
|
||||||
@ -627,7 +654,7 @@ class ConfigCommands(object):
|
|||||||
|
|
||||||
@args('param', nargs='?', default=None,
|
@args('param', nargs='?', default=None,
|
||||||
help='Configuration parameter to display (default: %(default)s)')
|
help='Configuration parameter to display (default: %(default)s)')
|
||||||
def list(self, param=None):
|
def list(self, param: Optional[str] = None) -> None:
|
||||||
"""List parameters configured for cinder.
|
"""List parameters configured for cinder.
|
||||||
|
|
||||||
Lists all parameters configured for cinder unless an optional argument
|
Lists all parameters configured for cinder unless an optional argument
|
||||||
@ -646,7 +673,7 @@ class ConfigCommands(object):
|
|||||||
class BackupCommands(object):
|
class BackupCommands(object):
|
||||||
"""Methods for managing backups."""
|
"""Methods for managing backups."""
|
||||||
|
|
||||||
def list(self):
|
def list(self) -> None:
|
||||||
"""List all backups.
|
"""List all backups.
|
||||||
|
|
||||||
List all backups (including ones in progress) and the host
|
List all backups (including ones in progress) and the host
|
||||||
@ -683,7 +710,7 @@ class BackupCommands(object):
|
|||||||
|
|
||||||
@args('--currenthost', required=True, help='Existing backup host name')
|
@args('--currenthost', required=True, help='Existing backup host name')
|
||||||
@args('--newhost', required=True, help='New backup host name')
|
@args('--newhost', required=True, help='New backup host name')
|
||||||
def update_backup_host(self, currenthost, newhost):
|
def update_backup_host(self, currenthost: str, newhost: str) -> None:
|
||||||
"""Modify the host name associated with a backup.
|
"""Modify the host name associated with a backup.
|
||||||
|
|
||||||
Particularly to recover from cases where one has moved
|
Particularly to recover from cases where one has moved
|
||||||
@ -738,7 +765,7 @@ class ServiceCommands(BaseCommand):
|
|||||||
help='Service to delete from the host.')
|
help='Service to delete from the host.')
|
||||||
@args('host_name', type=str,
|
@args('host_name', type=str,
|
||||||
help='Host from which to remove the service.')
|
help='Host from which to remove the service.')
|
||||||
def remove(self, binary, host_name):
|
def remove(self, binary: str, host_name: str) -> Optional[int]:
|
||||||
"""Completely removes a service."""
|
"""Completely removes a service."""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
try:
|
try:
|
||||||
@ -753,10 +780,12 @@ class ServiceCommands(BaseCommand):
|
|||||||
print(_("Service %(service)s on host %(host)s removed.") %
|
print(_("Service %(service)s on host %(host)s removed.") %
|
||||||
{'service': binary, 'host': host_name})
|
{'service': binary, 'host': host_name})
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ClusterCommands(BaseCommand):
|
class ClusterCommands(BaseCommand):
|
||||||
"""Methods for managing clusters."""
|
"""Methods for managing clusters."""
|
||||||
def list(self):
|
def list(self) -> None:
|
||||||
"""Show a list of all cinder services."""
|
"""Show a list of all cinder services."""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
clusters = objects.ClusterList.get_all(ctxt, services_summary=True)
|
clusters = objects.ClusterList.get_all(ctxt, services_summary=True)
|
||||||
@ -783,7 +812,10 @@ class ClusterCommands(BaseCommand):
|
|||||||
@args('binary', type=str,
|
@args('binary', type=str,
|
||||||
help='Service to delete from the cluster.')
|
help='Service to delete from the cluster.')
|
||||||
@args('cluster-name', type=str, help='Cluster to delete.')
|
@args('cluster-name', type=str, help='Cluster to delete.')
|
||||||
def remove(self, recursive, binary, cluster_name):
|
def remove(self,
|
||||||
|
recursive: bool,
|
||||||
|
binary: str,
|
||||||
|
cluster_name: str) -> Optional[int]:
|
||||||
"""Completely removes a cluster."""
|
"""Completely removes a cluster."""
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
try:
|
try:
|
||||||
@ -812,13 +844,18 @@ class ClusterCommands(BaseCommand):
|
|||||||
'removed.') % {'msg': msg, 'num': len(cluster.services)})
|
'removed.') % {'msg': msg, 'num': len(cluster.services)})
|
||||||
print(msg)
|
print(msg)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
@args('--full-rename', dest='partial',
|
@args('--full-rename', dest='partial',
|
||||||
action='store_false', default=True,
|
action='store_false', default=True,
|
||||||
help='Do full cluster rename instead of just replacing provided '
|
help='Do full cluster rename instead of just replacing provided '
|
||||||
'current cluster name and preserving backend and/or pool info.')
|
'current cluster name and preserving backend and/or pool info.')
|
||||||
@args('current', help='Current cluster name.')
|
@args('current', help='Current cluster name.')
|
||||||
@args('new', help='New cluster name.')
|
@args('new', help='New cluster name.')
|
||||||
def rename(self, partial, current, new):
|
def rename(self,
|
||||||
|
partial: bool,
|
||||||
|
current: Optional[str],
|
||||||
|
new: Optional[str]) -> Optional[int]:
|
||||||
"""Rename cluster name for Volumes and Consistency Groups.
|
"""Rename cluster name for Volumes and Consistency Groups.
|
||||||
|
|
||||||
Useful when you want to rename a cluster, particularly when the
|
Useful when you want to rename a cluster, particularly when the
|
||||||
@ -851,13 +888,15 @@ class ClusterCommands(BaseCommand):
|
|||||||
print(msg % {'current': current})
|
print(msg % {'current': current})
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ConsistencyGroupCommands(object):
|
class ConsistencyGroupCommands(object):
|
||||||
"""Methods for managing consistency groups."""
|
"""Methods for managing consistency groups."""
|
||||||
|
|
||||||
@args('--currenthost', required=True, help='Existing CG host name')
|
@args('--currenthost', required=True, help='Existing CG host name')
|
||||||
@args('--newhost', required=True, help='New CG host name')
|
@args('--newhost', required=True, help='New CG host name')
|
||||||
def update_cg_host(self, currenthost, newhost):
|
def update_cg_host(self, currenthost: str, newhost: str) -> None:
|
||||||
"""Modify the host name associated with a Consistency Group.
|
"""Modify the host name associated with a Consistency Group.
|
||||||
|
|
||||||
Particularly to recover from cases where one has moved
|
Particularly to recover from cases where one has moved
|
||||||
@ -878,7 +917,9 @@ class UtilCommands(object):
|
|||||||
"""Generic utils."""
|
"""Generic utils."""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_resources_locks():
|
def _get_resources_locks() -> Tuple[collections.defaultdict,
|
||||||
|
collections.defaultdict,
|
||||||
|
collections.defaultdict]:
|
||||||
"""Get all vol/snap/backup file lock paths."""
|
"""Get all vol/snap/backup file lock paths."""
|
||||||
backup_locks_prefix = 'cinder-cleanup_incomplete_backups_'
|
backup_locks_prefix = 'cinder-cleanup_incomplete_backups_'
|
||||||
oslo_dir = os.path.abspath(cfg.CONF.oslo_concurrency.lock_path)
|
oslo_dir = os.path.abspath(cfg.CONF.oslo_concurrency.lock_path)
|
||||||
@ -890,8 +931,8 @@ class UtilCommands(object):
|
|||||||
if tooz_dir != oslo_dir:
|
if tooz_dir != oslo_dir:
|
||||||
filenames += glob.glob(os.path.join(tooz_dir, 'cinder-*'))
|
filenames += glob.glob(os.path.join(tooz_dir, 'cinder-*'))
|
||||||
|
|
||||||
volumes = collections.defaultdict(list)
|
volumes: collections.defaultdict = collections.defaultdict(list)
|
||||||
snapshots = collections.defaultdict(list)
|
snapshots: collections.defaultdict = collections.defaultdict(list)
|
||||||
backups = collections.defaultdict(list)
|
backups = collections.defaultdict(list)
|
||||||
matcher = re.compile('.*?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-'
|
matcher = re.compile('.*?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-'
|
||||||
'[0-9a-f]{4}-[0-9a-f]{12}).*?', re.IGNORECASE)
|
'[0-9a-f]{4}-[0-9a-f]{12}).*?', re.IGNORECASE)
|
||||||
@ -908,7 +949,7 @@ class UtilCommands(object):
|
|||||||
|
|
||||||
return volumes, snapshots, backups
|
return volumes, snapshots, backups
|
||||||
|
|
||||||
def _exclude_running_backups(self, backups):
|
def _exclude_running_backups(self, backups: dict) -> None:
|
||||||
"""Remove backup entries from the dict for running backup services."""
|
"""Remove backup entries from the dict for running backup services."""
|
||||||
for backup_pgrp in list(backups.keys()):
|
for backup_pgrp in list(backups.keys()):
|
||||||
# The PGRP is the same as the PID of the parent process, so we know
|
# The PGRP is the same as the PID of the parent process, so we know
|
||||||
@ -928,7 +969,7 @@ class UtilCommands(object):
|
|||||||
@args('--services-offline', dest='online',
|
@args('--services-offline', dest='online',
|
||||||
action='store_false', default=True,
|
action='store_false', default=True,
|
||||||
help='All locks can be deleted as Cinder services are not running.')
|
help='All locks can be deleted as Cinder services are not running.')
|
||||||
def clean_locks(self, online):
|
def clean_locks(self, online: bool) -> None:
|
||||||
"""Clean file locks for vols, snaps, and backups on the current host.
|
"""Clean file locks for vols, snaps, and backups on the current host.
|
||||||
|
|
||||||
Should be run on any host where we are running a Cinder service (API,
|
Should be run on any host where we are running a Cinder service (API,
|
||||||
@ -955,6 +996,8 @@ class UtilCommands(object):
|
|||||||
self.ctxt = context.get_admin_context()
|
self.ctxt = context.get_admin_context()
|
||||||
# Find volume and snapshots ids, and backups PGRP based on the existing
|
# Find volume and snapshots ids, and backups PGRP based on the existing
|
||||||
# file locks
|
# file locks
|
||||||
|
volumes: Union[collections.defaultdict, dict]
|
||||||
|
snapshots: Union[collections.defaultdict, dict]
|
||||||
volumes, snapshots, backups = self._get_resources_locks()
|
volumes, snapshots, backups = self._get_resources_locks()
|
||||||
|
|
||||||
# If services are online we cannot delete locks for existing resources
|
# If services are online we cannot delete locks for existing resources
|
||||||
@ -999,7 +1042,7 @@ CATEGORIES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def methods_of(obj):
|
def methods_of(obj) -> list:
|
||||||
"""Return non-private methods from an object.
|
"""Return non-private methods from an object.
|
||||||
|
|
||||||
Get all callable methods of an object that don't start with underscore
|
Get all callable methods of an object that don't start with underscore
|
||||||
@ -1007,13 +1050,14 @@ def methods_of(obj):
|
|||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
for i in dir(obj):
|
for i in dir(obj):
|
||||||
if isinstance(getattr(obj, i),
|
if (isinstance(getattr(obj, i),
|
||||||
collections_abc.Callable) and not i.startswith('_'):
|
collections_abc.Callable) and # type: ignore
|
||||||
|
not i.startswith('_')):
|
||||||
result.append((i, getattr(obj, i)))
|
result.append((i, getattr(obj, i)))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def missing_action(help_func):
|
def missing_action(help_func: Callable) -> Callable:
|
||||||
def wrapped():
|
def wrapped():
|
||||||
help_func()
|
help_func()
|
||||||
exit(2)
|
exit(2)
|
||||||
@ -1033,7 +1077,7 @@ def add_command_parsers(subparsers):
|
|||||||
for (action, action_fn) in methods_of(command_object):
|
for (action, action_fn) in methods_of(command_object):
|
||||||
parser = category_subparsers.add_parser(action)
|
parser = category_subparsers.add_parser(action)
|
||||||
|
|
||||||
action_kwargs = []
|
action_kwargs: list = []
|
||||||
for args, kwargs in getattr(action_fn, 'args', []):
|
for args, kwargs in getattr(action_fn, 'args', []):
|
||||||
parser.add_argument(*args, **kwargs)
|
parser.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ cinder/context.py
|
|||||||
cinder/coordination.py
|
cinder/coordination.py
|
||||||
cinder/cmd/api.py
|
cinder/cmd/api.py
|
||||||
cinder/cmd/backup.py
|
cinder/cmd/backup.py
|
||||||
|
cinder/cmd/manage.py
|
||||||
cinder/cmd/scheduler.py
|
cinder/cmd/scheduler.py
|
||||||
cinder/cmd/status.py
|
cinder/cmd/status.py
|
||||||
cinder/cmd/volume.py
|
cinder/cmd/volume.py
|
||||||
|
Loading…
Reference in New Issue
Block a user