mypy: backup

Change-Id: I8ee0e214eb1c1fe5a26304055737dd36cefec6ec
This commit is contained in:
Eric Harney 2021-04-19 15:40:32 -04:00
parent cf7c2fcc75
commit ce34288e47
4 changed files with 94 additions and 36 deletions

View File

@ -19,6 +19,7 @@
from datetime import datetime from datetime import datetime
import random import random
from typing import List, Optional # noqa: H301
from eventlet import greenthread from eventlet import greenthread
from oslo_config import cfg from oslo_config import cfg
@ -65,17 +66,24 @@ class API(base.Base):
self.volume_api = cinder.volume.API() self.volume_api = cinder.volume.API()
super().__init__() 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) backup = objects.Backup.get_by_id(context, backup_id)
context.authorize(policy.GET_POLICY, target_obj=backup) context.authorize(policy.GET_POLICY, target_obj=backup)
return 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, result = self.backup_rpcapi.check_support_to_force_delete(context,
backup_host) backup_host)
return result 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. """Make the RPC call to delete a volume backup.
Call backup manager to execute backup delete or force delete operation. Call backup manager to execute backup delete or force delete operation.
@ -109,8 +117,14 @@ class API(base.Base):
backup.save() backup.save()
self.backup_rpcapi.delete_backup(context, backup) self.backup_rpcapi.delete_backup(context, backup)
def get_all(self, context, search_opts=None, marker=None, limit=None, def get_all(self,
offset=None, sort_keys=None, sort_dirs=None): 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) context.authorize(policy.GET_ALL_POLICY)
search_opts = search_opts or {} search_opts = search_opts or {}
@ -132,11 +146,15 @@ class API(base.Base):
return backups 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 return ((not availability_zone) or
service.availability_zone == availability_zone) 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.""" """Check if there is a backup service available."""
topic = constants.BACKUP_TOPIC topic = constants.BACKUP_TOPIC
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
@ -148,7 +166,9 @@ class API(base.Base):
return True return True
return False 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.
Get an available backup service host in the specified Get an available backup service host in the specified
@ -166,10 +186,10 @@ class API(base.Base):
idx = idx + 1 idx = idx + 1
return None 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) 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.""" """Return an appropriate backup service host."""
backup_host = None backup_host = None
if not host or not CONF.backup_use_same_host: 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') raise exception.ServiceNotFound(service_id='cinder-backup')
return backup_host return backup_host
def _list_backup_services(self): def _list_backup_services(self) -> List['objects.Service']:
"""List all enabled backup services. """List all enabled backup services.
:returns: list -- hosts for services that are enabled for backup. :returns: list -- hosts for services that are enabled for backup.
@ -191,14 +211,22 @@ class API(base.Base):
ctxt, topic, disabled=False) ctxt, topic, disabled=False)
return services return services
def _list_backup_hosts(self): def _list_backup_hosts(self) -> list:
services = self._list_backup_services() services = self._list_backup_services()
return [srv.host for srv in services return [srv.host for srv in services
if not srv.disabled and srv.is_up] if not srv.disabled and srv.is_up]
def create(self, context, name, description, volume_id, def create(self,
container, incremental=False, availability_zone=None, context: context.RequestContext,
force=False, snapshot_id=None, metadata=None): 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.""" """Make the RPC call to create a volume backup."""
volume = self.volume_api.get(context, volume_id) volume = self.volume_api.get(context, volume_id)
context.authorize(policy.CREATE_POLICY, target_obj=volume) context.authorize(policy.CREATE_POLICY, target_obj=volume)
@ -334,7 +362,11 @@ class API(base.Base):
return backup 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.""" """Make the RPC call to restore a volume backup."""
backup = self.get(context, backup_id) backup = self.get(context, backup_id)
context.authorize(policy.RESTORE_POLICY, target_obj=backup) context.authorize(policy.RESTORE_POLICY, target_obj=backup)
@ -410,7 +442,10 @@ class API(base.Base):
return d 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. """Make the RPC call to reset a volume backup's status.
Call backup manager to execute backup status reset operation. 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, self.backup_rpcapi.reset_status(ctxt=context, backup=backup,
status=status) 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. """Make the RPC call to export a volume backup.
Call backup manager to execute backup export. Call backup manager to execute backup export.
@ -462,7 +499,9 @@ class API(base.Base):
return export_data 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. """Prepare database backup record for import.
This method decodes provided backup_url and expects to find the id of 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) QUOTAS.rollback(context, reservations)
return backup 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. """Make the RPC call to import a volume backup.
:param context: running context :param context: running context
@ -588,7 +630,10 @@ class API(base.Base):
return backup 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) backup = self.get(context, backup_id)
context.authorize(policy.UPDATE_POLICY, target_obj=backup) context.authorize(policy.UPDATE_POLICY, target_obj=backup)
backup.update(fields) backup.update(fields)

View File

@ -70,7 +70,7 @@ class BackupAPI(rpc.RPCAPI):
cctxt = self._get_cctxt(server=backup.host) cctxt = self._get_cctxt(server=backup.host)
cctxt.cast(ctxt, 'delete_backup', backup=backup) 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 " LOG.debug("export_record in rpcapi backup_id %(id)s "
"on host %(host)s.", "on host %(host)s.",
{'id': backup.id, {'id': backup.id,
@ -79,7 +79,7 @@ class BackupAPI(rpc.RPCAPI):
return cctxt.call(ctxt, 'export_record', backup=backup) return cctxt.call(ctxt, 'export_record', backup=backup)
def import_record(self, ctxt, host, backup, backup_service, backup_url, 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 " LOG.debug("import_record rpcapi backup id %(id)s "
"on host %(host)s for backup_url %(url)s.", "on host %(host)s for backup_url %(url)s.",
{'id': backup.id, 'host': host, 'url': backup_url}) {'id': backup.id, 'host': host, 'url': backup_url})
@ -97,7 +97,7 @@ class BackupAPI(rpc.RPCAPI):
cctxt = self._get_cctxt(server=backup.host) cctxt = self._get_cctxt(server=backup.host)
return cctxt.cast(ctxt, 'reset_status', backup=backup, status=status) 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 " LOG.debug("Check if backup driver supports force delete "
"on host %(host)s.", {'host': host}) "on host %(host)s.", {'host': host})
cctxt = self._get_cctxt(server=host) cctxt = self._get_cctxt(server=host)

View File

@ -17,6 +17,7 @@ from oslo_serialization import base64
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_versionedobjects import fields from oslo_versionedobjects import fields
from cinder import context
from cinder import db from cinder import db
from cinder import exception from cinder import exception
from cinder.i18n import _ from cinder.i18n import _
@ -103,15 +104,17 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
return CONF.backup_name_template % self.id return CONF.backup_name_template % self.id
@property @property
def is_incremental(self): def is_incremental(self) -> bool:
return bool(self.parent_id) return bool(self.parent_id)
@property @property
def has_dependent_backups(self): def has_dependent_backups(self) -> bool:
return bool(self.num_dependent_backups) return bool(self.num_dependent_backups)
@classmethod @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: if expected_attrs is None:
expected_attrs = [] expected_attrs = []
for name, field in backup.fields.items(): for name, field in backup.fields.items():
@ -159,7 +162,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
return changes return changes
def create(self): def create(self) -> None:
if self.obj_attr_is_set('id'): if self.obj_attr_is_set('id'):
raise exception.ObjectActionError(action='create', raise exception.ObjectActionError(action='create',
reason='already created') reason='already created')
@ -168,7 +171,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
db_backup = db.backup_create(self._context, updates) db_backup = db.backup_create(self._context, updates)
self._from_db_object(self._context, self, db_backup) self._from_db_object(self._context, self, db_backup)
def save(self): def save(self) -> None:
updates = self.cinder_obj_get_changes() updates = self.cinder_obj_get_changes()
if updates: if updates:
if 'metadata' in updates: if 'metadata' in updates:
@ -181,14 +184,14 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
self.obj_reset_changes() self.obj_reset_changes()
def destroy(self): def destroy(self) -> None:
with self.obj_as_admin(): with self.obj_as_admin():
updated_values = db.backup_destroy(self._context, self.id) updated_values = db.backup_destroy(self._context, self.id)
self.update(updated_values) self.update(updated_values)
self.obj_reset_changes(updated_values.keys()) self.obj_reset_changes(updated_values.keys())
@staticmethod @staticmethod
def decode_record(backup_url): def decode_record(backup_url) -> dict:
"""Deserialize backup metadata from string into a dictionary. """Deserialize backup metadata from string into a dictionary.
:raises InvalidInput: :raises InvalidInput:
@ -201,7 +204,7 @@ class Backup(base.CinderPersistentObject, base.CinderObject,
msg = _("Can't parse backup record.") msg = _("Can't parse backup record.")
raise exception.InvalidInput(reason=msg) 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.""" """Serialize backup object, with optional extra info, into a string."""
# We don't want to export extra fields and we want to force lazy # 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 # loading, so we can't use dict(self) or self.obj_to_primitive
@ -223,8 +226,10 @@ class BackupList(base.ObjectListBase, base.CinderObject):
} }
@classmethod @classmethod
def get_all(cls, context, filters=None, marker=None, limit=None, def get_all(cls,
offset=None, sort_keys=None, sort_dirs=None): 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, backups = db.backup_get_all(context, filters, marker, limit, offset,
sort_keys, sort_dirs) sort_keys, sort_dirs)
expected_attrs = Backup._get_expected_attrs(context) expected_attrs = Backup._get_expected_attrs(context)
@ -232,7 +237,9 @@ class BackupList(base.ObjectListBase, base.CinderObject):
backups, expected_attrs=expected_attrs) backups, expected_attrs=expected_attrs)
@classmethod @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) backups = db.backup_get_all_by_host(context, host)
expected_attrs = Backup._get_expected_attrs(context) expected_attrs = Backup._get_expected_attrs(context)
return base.obj_make_list(context, cls(context), objects.Backup, return base.obj_make_list(context, cls(context), objects.Backup,
@ -251,7 +258,11 @@ class BackupList(base.ObjectListBase, base.CinderObject):
@classmethod @classmethod
def get_all_by_volume( 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( backups = db.backup_get_all_by_volume(
context, volume_id, vol_project_id, filters) context, volume_id, vol_project_id, filters)
expected_attrs = Backup._get_expected_attrs(context) expected_attrs = Backup._get_expected_attrs(context)

View File

@ -1,3 +1,4 @@
cinder/backup/api.py
cinder/backup/manager.py cinder/backup/manager.py
cinder/common/constants.py cinder/common/constants.py
cinder/context.py cinder/context.py
@ -8,6 +9,7 @@ cinder/image/glance.py
cinder/image/image_utils.py cinder/image/image_utils.py
cinder/exception.py cinder/exception.py
cinder/manager.py cinder/manager.py
cinder/objects/backup.py
cinder/scheduler/base_handler.py cinder/scheduler/base_handler.py
cinder/scheduler/base_weight.py cinder/scheduler/base_weight.py
cinder/scheduler/evaluator/evaluator.py cinder/scheduler/evaluator/evaluator.py