diff --git a/cinder/backup/api.py b/cinder/backup/api.py index f04f33f73c6..b9292513dbf 100644 --- a/cinder/backup/api.py +++ b/cinder/backup/api.py @@ -19,6 +19,7 @@ from datetime import datetime import random +from typing import List, Optional # noqa: H301 from eventlet import greenthread from oslo_config import cfg @@ -65,17 +66,24 @@ class API(base.Base): self.volume_api = cinder.volume.API() super().__init__() - def get(self, context, backup_id): + def get(self, + context: context.RequestContext, + backup_id: str) -> 'objects.Backup': backup = objects.Backup.get_by_id(context, backup_id) context.authorize(policy.GET_POLICY, target_obj=backup) return backup - def _check_support_to_force_delete(self, context, backup_host): + def _check_support_to_force_delete(self, + context: context.RequestContext, + backup_host: str) -> bool: result = self.backup_rpcapi.check_support_to_force_delete(context, backup_host) return result - def delete(self, context, backup, force=False): + def delete(self, + context: context.RequestContext, + backup: 'objects.Backup', + force: bool = False) -> None: """Make the RPC call to delete a volume backup. Call backup manager to execute backup delete or force delete operation. @@ -109,8 +117,14 @@ class API(base.Base): backup.save() self.backup_rpcapi.delete_backup(context, backup) - def get_all(self, context, search_opts=None, marker=None, limit=None, - offset=None, sort_keys=None, sort_dirs=None): + def get_all(self, + context: context.RequestContext, + search_opts: dict = None, + marker: str = None, + limit: int = None, + offset: int = None, + sort_keys: List[str] = None, + sort_dirs: List[str] = None) -> 'objects.BackupList': context.authorize(policy.GET_ALL_POLICY) search_opts = search_opts or {} @@ -132,11 +146,15 @@ class API(base.Base): return backups - def _az_matched(self, service, availability_zone): + def _az_matched(self, + service: 'objects.Service', + availability_zone: str) -> bool: return ((not availability_zone) or service.availability_zone == availability_zone) - def _is_backup_service_enabled(self, availability_zone, host): + def _is_backup_service_enabled(self, + availability_zone: str, + host: str) -> bool: """Check if there is a backup service available.""" topic = constants.BACKUP_TOPIC ctxt = context.get_admin_context() @@ -148,7 +166,9 @@ class API(base.Base): return True return False - def _get_any_available_backup_service(self, availability_zone): + def _get_any_available_backup_service( + self, + availability_zone: str) -> Optional[str]: """Get an available backup service host. Get an available backup service host in the specified @@ -166,10 +186,10 @@ class API(base.Base): idx = idx + 1 return None - def get_available_backup_service_host(self, host, az): + def get_available_backup_service_host(self, host: str, az: str) -> str: return self._get_available_backup_service_host(host, az) - def _get_available_backup_service_host(self, host, az): + def _get_available_backup_service_host(self, host: str, az: str) -> str: """Return an appropriate backup service host.""" backup_host = None if not host or not CONF.backup_use_same_host: @@ -180,7 +200,7 @@ class API(base.Base): raise exception.ServiceNotFound(service_id='cinder-backup') return backup_host - def _list_backup_services(self): + def _list_backup_services(self) -> List['objects.Service']: """List all enabled backup services. :returns: list -- hosts for services that are enabled for backup. @@ -191,14 +211,22 @@ class API(base.Base): ctxt, topic, disabled=False) return services - def _list_backup_hosts(self): + def _list_backup_hosts(self) -> list: services = self._list_backup_services() return [srv.host for srv in services if not srv.disabled and srv.is_up] - def create(self, context, name, description, volume_id, - container, incremental=False, availability_zone=None, - force=False, snapshot_id=None, metadata=None): + def create(self, + context: context.RequestContext, + name: Optional[str], + description: Optional[str], + volume_id: str, + container: str, + incremental: bool = False, + availability_zone: str = None, + force: bool = False, + snapshot_id: Optional[str] = None, + metadata: dict = None) -> 'objects.Backup': """Make the RPC call to create a volume backup.""" volume = self.volume_api.get(context, volume_id) context.authorize(policy.CREATE_POLICY, target_obj=volume) @@ -334,7 +362,11 @@ class API(base.Base): return backup - def restore(self, context, backup_id, volume_id=None, name=None): + def restore(self, + context: context.RequestContext, + backup_id: str, + volume_id: str = None, + name: str = None) -> dict: """Make the RPC call to restore a volume backup.""" backup = self.get(context, backup_id) context.authorize(policy.RESTORE_POLICY, target_obj=backup) @@ -410,7 +442,10 @@ class API(base.Base): return d - def reset_status(self, context, backup_id, status): + def reset_status(self, + context: context.RequestContext, + backup_id: str, + status: str) -> None: """Make the RPC call to reset a volume backup's status. Call backup manager to execute backup status reset operation. @@ -431,7 +466,9 @@ class API(base.Base): self.backup_rpcapi.reset_status(ctxt=context, backup=backup, status=status) - def export_record(self, context, backup_id): + def export_record(self, + context: context.RequestContext, + backup_id: str) -> dict: """Make the RPC call to export a volume backup. Call backup manager to execute backup export. @@ -462,7 +499,9 @@ class API(base.Base): return export_data - def _get_import_backup(self, context, backup_url): + def _get_import_backup(self, + context: context.RequestContext, + backup_url: str) -> 'objects.Backup': """Prepare database backup record for import. This method decodes provided backup_url and expects to find the id of @@ -553,7 +592,10 @@ class API(base.Base): QUOTAS.rollback(context, reservations) return backup - def import_record(self, context, backup_service, backup_url): + def import_record(self, + context: context.RequestContext, + backup_service: str, + backup_url: str) -> 'objects.Backup': """Make the RPC call to import a volume backup. :param context: running context @@ -588,7 +630,10 @@ class API(base.Base): return backup - def update(self, context, backup_id, fields): + def update(self, + context: context.RequestContext, + backup_id: str, + fields: list) -> 'objects.Service': backup = self.get(context, backup_id) context.authorize(policy.UPDATE_POLICY, target_obj=backup) backup.update(fields) diff --git a/cinder/backup/rpcapi.py b/cinder/backup/rpcapi.py index 981526fcc86..e65c69007a2 100644 --- a/cinder/backup/rpcapi.py +++ b/cinder/backup/rpcapi.py @@ -70,7 +70,7 @@ class BackupAPI(rpc.RPCAPI): cctxt = self._get_cctxt(server=backup.host) cctxt.cast(ctxt, 'delete_backup', backup=backup) - def export_record(self, ctxt, backup): + def export_record(self, ctxt, backup) -> dict: LOG.debug("export_record in rpcapi backup_id %(id)s " "on host %(host)s.", {'id': backup.id, @@ -79,7 +79,7 @@ class BackupAPI(rpc.RPCAPI): return cctxt.call(ctxt, 'export_record', backup=backup) def import_record(self, ctxt, host, backup, backup_service, backup_url, - backup_hosts): + backup_hosts) -> None: LOG.debug("import_record rpcapi backup id %(id)s " "on host %(host)s for backup_url %(url)s.", {'id': backup.id, 'host': host, 'url': backup_url}) @@ -97,7 +97,7 @@ class BackupAPI(rpc.RPCAPI): cctxt = self._get_cctxt(server=backup.host) return cctxt.cast(ctxt, 'reset_status', backup=backup, status=status) - def check_support_to_force_delete(self, ctxt, host): + def check_support_to_force_delete(self, ctxt, host) -> bool: LOG.debug("Check if backup driver supports force delete " "on host %(host)s.", {'host': host}) cctxt = self._get_cctxt(server=host) diff --git a/cinder/objects/backup.py b/cinder/objects/backup.py index a056713f865..e15b82d5fd9 100644 --- a/cinder/objects/backup.py +++ b/cinder/objects/backup.py @@ -17,6 +17,7 @@ from oslo_serialization import base64 from oslo_serialization import jsonutils from oslo_versionedobjects import fields +from cinder import context from cinder import db from cinder import exception from cinder.i18n import _ @@ -103,15 +104,17 @@ class Backup(base.CinderPersistentObject, base.CinderObject, return CONF.backup_name_template % self.id @property - def is_incremental(self): + def is_incremental(self) -> bool: return bool(self.parent_id) @property - def has_dependent_backups(self): + def has_dependent_backups(self) -> bool: return bool(self.num_dependent_backups) @classmethod - def _from_db_object(cls, context, backup, db_backup, expected_attrs=None): + def _from_db_object(cls, + context: context.RequestContext, + backup, db_backup, expected_attrs=None) -> 'Backup': if expected_attrs is None: expected_attrs = [] for name, field in backup.fields.items(): @@ -159,7 +162,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject, return changes - def create(self): + def create(self) -> None: if self.obj_attr_is_set('id'): raise exception.ObjectActionError(action='create', reason='already created') @@ -168,7 +171,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject, db_backup = db.backup_create(self._context, updates) self._from_db_object(self._context, self, db_backup) - def save(self): + def save(self) -> None: updates = self.cinder_obj_get_changes() if updates: if 'metadata' in updates: @@ -181,14 +184,14 @@ class Backup(base.CinderPersistentObject, base.CinderObject, self.obj_reset_changes() - def destroy(self): + def destroy(self) -> None: with self.obj_as_admin(): updated_values = db.backup_destroy(self._context, self.id) self.update(updated_values) self.obj_reset_changes(updated_values.keys()) @staticmethod - def decode_record(backup_url): + def decode_record(backup_url) -> dict: """Deserialize backup metadata from string into a dictionary. :raises InvalidInput: @@ -201,7 +204,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject, msg = _("Can't parse backup record.") raise exception.InvalidInput(reason=msg) - def encode_record(self, **kwargs): + def encode_record(self, **kwargs) -> str: """Serialize backup object, with optional extra info, into a string.""" # We don't want to export extra fields and we want to force lazy # loading, so we can't use dict(self) or self.obj_to_primitive @@ -223,8 +226,10 @@ class BackupList(base.ObjectListBase, base.CinderObject): } @classmethod - def get_all(cls, context, filters=None, marker=None, limit=None, - offset=None, sort_keys=None, sort_dirs=None): + def get_all(cls, + context: context.RequestContext, + filters=None, marker=None, limit=None, + offset=None, sort_keys=None, sort_dirs=None) -> 'BackupList': backups = db.backup_get_all(context, filters, marker, limit, offset, sort_keys, sort_dirs) expected_attrs = Backup._get_expected_attrs(context) @@ -232,7 +237,9 @@ class BackupList(base.ObjectListBase, base.CinderObject): backups, expected_attrs=expected_attrs) @classmethod - def get_all_by_host(cls, context, host): + def get_all_by_host(cls, + context: context.RequestContext, + host: str) -> 'BackupList': backups = db.backup_get_all_by_host(context, host) expected_attrs = Backup._get_expected_attrs(context) return base.obj_make_list(context, cls(context), objects.Backup, @@ -251,7 +258,11 @@ class BackupList(base.ObjectListBase, base.CinderObject): @classmethod def get_all_by_volume( - cls, context, volume_id, vol_project_id, filters=None): + cls, + context: context.RequestContext, + volume_id: str, + vol_project_id: str, + filters=None) -> 'BackupList': backups = db.backup_get_all_by_volume( context, volume_id, vol_project_id, filters) expected_attrs = Backup._get_expected_attrs(context) diff --git a/mypy-files.txt b/mypy-files.txt index 6e6d8d1cda8..1e6d60cdef5 100644 --- a/mypy-files.txt +++ b/mypy-files.txt @@ -1,3 +1,4 @@ +cinder/backup/api.py cinder/backup/manager.py cinder/common/constants.py cinder/context.py @@ -8,6 +9,7 @@ cinder/image/glance.py cinder/image/image_utils.py cinder/exception.py cinder/manager.py +cinder/objects/backup.py cinder/scheduler/base_handler.py cinder/scheduler/base_weight.py cinder/scheduler/evaluator/evaluator.py