Merge "Use modern type annotation format for collections"
This commit is contained in:
commit
be71720bb9
@ -17,9 +17,11 @@
|
|||||||
|
|
||||||
"""Handles all requests relating to the volume backups service."""
|
"""Handles all requests relating to the volume backups service."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import random
|
import random
|
||||||
from typing import List, Optional # noqa: H301
|
from typing import Optional
|
||||||
|
|
||||||
from eventlet import greenthread
|
from eventlet import greenthread
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -123,8 +125,8 @@ class API(base.Base):
|
|||||||
marker: Optional[str] = None,
|
marker: Optional[str] = None,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
offset: Optional[int] = None,
|
offset: Optional[int] = None,
|
||||||
sort_keys: Optional[List[str]] = None,
|
sort_keys: Optional[list[str]] = None,
|
||||||
sort_dirs: Optional[List[str]] = None) -> 'objects.BackupList':
|
sort_dirs: Optional[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 {}
|
||||||
@ -200,7 +202,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) -> List['objects.Service']:
|
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.
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
"""RequestContext: context for requests that persist through all of cinder."""
|
"""RequestContext: context for requests that persist through all of cinder."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from typing import Any, Dict, Optional # noqa: H301
|
from typing import Any, Optional # noqa: H301
|
||||||
|
|
||||||
from keystoneauth1.access import service_catalog as ksa_service_catalog
|
from keystoneauth1.access import service_catalog as ksa_service_catalog
|
||||||
from keystoneauth1 import plugin
|
from keystoneauth1 import plugin
|
||||||
@ -162,7 +164,7 @@ class RequestContext(context.RequestContext):
|
|||||||
read_deleted = property(_get_read_deleted, _set_read_deleted,
|
read_deleted = property(_get_read_deleted, _set_read_deleted,
|
||||||
_del_read_deleted)
|
_del_read_deleted)
|
||||||
|
|
||||||
def to_dict(self) -> Dict[str, Any]:
|
def to_dict(self) -> dict[str, Any]:
|
||||||
result = super(RequestContext, self).to_dict()
|
result = super(RequestContext, self).to_dict()
|
||||||
result['user_id'] = self.user_id
|
result['user_id'] = self.user_id
|
||||||
result['project_id'] = self.project_id
|
result['project_id'] = self.project_id
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from typing import Any, List # noqa: H301
|
from typing import Any
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
# For more information please visit: https://wiki.openstack.org/wiki/TaskFlow
|
# For more information please visit: https://wiki.openstack.org/wiki/TaskFlow
|
||||||
@ -25,7 +27,7 @@ from cinder import exception
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _make_task_name(cls, addons: List[str] = None) -> str:
|
def _make_task_name(cls, addons: list[str] = None) -> str:
|
||||||
"""Makes a pretty name for a task class."""
|
"""Makes a pretty name for a task class."""
|
||||||
base_name = ".".join([cls.__module__, cls.__name__])
|
base_name = ".".join([cls.__module__, cls.__name__])
|
||||||
extra = ''
|
extra = ''
|
||||||
@ -41,11 +43,11 @@ class CinderTask(task.Task):
|
|||||||
implement the given task as the task name.
|
implement the given task as the task name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, addons: List[str] = None, **kwargs: Any) -> None:
|
def __init__(self, addons: list[str] = None, **kwargs: Any) -> None:
|
||||||
super(CinderTask, self).__init__(self.make_name(addons), **kwargs)
|
super(CinderTask, self).__init__(self.make_name(addons), **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_name(cls, addons: List[str] = None) -> str:
|
def make_name(cls, addons: list[str] = None) -> str:
|
||||||
return _make_task_name(cls, addons)
|
return _make_task_name(cls, addons)
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
"""Implementation of an image service that uses Glance as the backend"""
|
"""Implementation of an image service that uses Glance as the backend"""
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import itertools
|
import itertools
|
||||||
import random
|
import random
|
||||||
@ -23,8 +25,7 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
from typing import (Any, Callable, Dict, Iterable, List, # noqa: H301
|
from typing import (Any, Callable, Iterable, NoReturn, Optional) # noqa: H301
|
||||||
NoReturn, Optional, Tuple) # noqa: H301
|
|
||||||
import urllib
|
import urllib
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ _SESSION = None
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _parse_image_ref(image_href: str) -> Tuple[str, str, bool]:
|
def _parse_image_ref(image_href: str) -> tuple[str, str, bool]:
|
||||||
"""Parse an image href into composite parts.
|
"""Parse an image href into composite parts.
|
||||||
|
|
||||||
:param image_href: href of an image
|
:param image_href: href of an image
|
||||||
@ -283,7 +284,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def detail(self,
|
def detail(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
**kwargs: str) -> List[dict]:
|
**kwargs: str) -> list[dict]:
|
||||||
"""Calls out to Glance for a list of detailed image information."""
|
"""Calls out to Glance for a list of detailed image information."""
|
||||||
params = self._extract_query_params(kwargs)
|
params = self._extract_query_params(kwargs)
|
||||||
try:
|
try:
|
||||||
@ -298,7 +299,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
return _images
|
return _images
|
||||||
|
|
||||||
def _extract_query_params(self, params: dict) -> Dict[str, Any]:
|
def _extract_query_params(self, params: dict) -> dict[str, Any]:
|
||||||
_params = {}
|
_params = {}
|
||||||
accepted_params = ('filters', 'marker', 'limit',
|
accepted_params = ('filters', 'marker', 'limit',
|
||||||
'sort_key', 'sort_dir')
|
'sort_key', 'sort_dir')
|
||||||
@ -310,7 +311,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def list_members(self,
|
def list_members(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image_id: str) -> List[dict]:
|
image_id: str) -> list[dict]:
|
||||||
"""Returns a list of dicts with image member data."""
|
"""Returns a list of dicts with image member data."""
|
||||||
try:
|
try:
|
||||||
return self._client.call(context,
|
return self._client.call(context,
|
||||||
@ -330,7 +331,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def show(self,
|
def show(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image_id: str) -> Dict[str, Any]:
|
image_id: str) -> dict[str, Any]:
|
||||||
"""Returns a dict with image data for the given opaque image id."""
|
"""Returns a dict with image data for the given opaque image id."""
|
||||||
try:
|
try:
|
||||||
image = self._client.call(context, 'get', image_id)
|
image = self._client.call(context, 'get', image_id)
|
||||||
@ -345,7 +346,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def get_location(self,
|
def get_location(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image_id: str) -> Tuple[Optional[str], Any]:
|
image_id: str) -> tuple[Optional[str], Any]:
|
||||||
"""Get backend storage location url.
|
"""Get backend storage location url.
|
||||||
|
|
||||||
Returns a tuple containing the direct url and locations representing
|
Returns a tuple containing the direct url and locations representing
|
||||||
@ -421,8 +422,8 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def create(self,
|
def create(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image_meta: Dict[str, Any],
|
image_meta: dict[str, Any],
|
||||||
data=None) -> Dict[str, Any]:
|
data=None) -> dict[str, Any]:
|
||||||
"""Store the image data and return the new image object."""
|
"""Store the image data and return the new image object."""
|
||||||
sent_service_image_meta = self._translate_to_glance(image_meta)
|
sent_service_image_meta = self._translate_to_glance(image_meta)
|
||||||
|
|
||||||
@ -497,7 +498,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def _translate_from_glance(self,
|
def _translate_from_glance(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image: Dict[str, Any]) -> dict:
|
image: dict[str, Any]) -> dict:
|
||||||
"""Get image metadata from glance image.
|
"""Get image metadata from glance image.
|
||||||
|
|
||||||
Extract metadata from image and convert it's properties
|
Extract metadata from image and convert it's properties
|
||||||
@ -536,7 +537,7 @@ class GlanceImageService(object):
|
|||||||
return image_meta
|
return image_meta
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _translate_to_glance(image_meta: Dict[str, Any]) -> Dict[str, Any]:
|
def _translate_to_glance(image_meta: dict[str, Any]) -> dict[str, Any]:
|
||||||
image_meta = _convert_to_string(image_meta)
|
image_meta = _convert_to_string(image_meta)
|
||||||
image_meta = _remove_read_only(image_meta)
|
image_meta = _remove_read_only(image_meta)
|
||||||
|
|
||||||
@ -684,7 +685,7 @@ def _translate_plain_exception(exc_value: BaseException) -> BaseException:
|
|||||||
|
|
||||||
|
|
||||||
def get_remote_image_service(context: context.RequestContext,
|
def get_remote_image_service(context: context.RequestContext,
|
||||||
image_href) -> Tuple[GlanceImageService, str]:
|
image_href) -> tuple[GlanceImageService, str]:
|
||||||
"""Create an image_service and parse the id from the given image_href.
|
"""Create an image_service and parse the id from the given image_href.
|
||||||
|
|
||||||
The image_href param can be an href of the form
|
The image_href param can be an href of the form
|
||||||
|
@ -23,6 +23,7 @@ Some slight modifications, but at some point
|
|||||||
we should look at maybe pushing this up to Oslo
|
we should look at maybe pushing this up to Oslo
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
@ -31,8 +32,7 @@ import math
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import (ContextManager, Dict, Generator, # noqa: H301
|
from typing import ContextManager, Generator, Optional # noqa: H301
|
||||||
List, Optional, Tuple)
|
|
||||||
|
|
||||||
import cryptography
|
import cryptography
|
||||||
from cursive import exception as cursive_exception
|
from cursive import exception as cursive_exception
|
||||||
@ -152,7 +152,7 @@ def qemu_img_info(path: str,
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def get_qemu_img_version() -> Optional[List[int]]:
|
def get_qemu_img_version() -> Optional[list[int]]:
|
||||||
"""The qemu-img version will be cached until the process is restarted."""
|
"""The qemu-img version will be cached until the process is restarted."""
|
||||||
|
|
||||||
global QEMU_IMG_VERSION
|
global QEMU_IMG_VERSION
|
||||||
@ -187,8 +187,7 @@ def _get_qemu_convert_luks_cmd(src: str,
|
|||||||
cipher_spec: Optional[dict] = None,
|
cipher_spec: Optional[dict] = None,
|
||||||
passphrase_file: Optional[str] = None,
|
passphrase_file: Optional[str] = None,
|
||||||
src_passphrase_file: Optional[str] = None) \
|
src_passphrase_file: Optional[str] = None) \
|
||||||
-> List[str]:
|
-> list[str]:
|
||||||
|
|
||||||
cmd = ['qemu-img', 'convert']
|
cmd = ['qemu-img', 'convert']
|
||||||
|
|
||||||
if prefix:
|
if prefix:
|
||||||
@ -223,8 +222,7 @@ def _get_qemu_convert_cmd(src: str,
|
|||||||
passphrase_file: Optional[str] = None,
|
passphrase_file: Optional[str] = None,
|
||||||
compress: bool = False,
|
compress: bool = False,
|
||||||
src_passphrase_file: Optional[str] = None) \
|
src_passphrase_file: Optional[str] = None) \
|
||||||
-> List[str]:
|
-> list[str]:
|
||||||
|
|
||||||
if src_passphrase_file is not None:
|
if src_passphrase_file is not None:
|
||||||
if passphrase_file is None:
|
if passphrase_file is None:
|
||||||
message = _("Can't create unencrypted volume %(format)s "
|
message = _("Can't create unencrypted volume %(format)s "
|
||||||
@ -290,7 +288,7 @@ def _get_qemu_convert_cmd(src: str,
|
|||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def _get_version_from_string(version_string: str) -> List[int]:
|
def _get_version_from_string(version_string: str) -> list[int]:
|
||||||
return [int(x) for x in version_string.split('.')]
|
return [int(x) for x in version_string.split('.')]
|
||||||
|
|
||||||
|
|
||||||
@ -451,7 +449,7 @@ def resize_image(source: str,
|
|||||||
run_as_root: bool = False,
|
run_as_root: bool = False,
|
||||||
file_format: Optional[str] = None) -> None:
|
file_format: Optional[str] = None) -> None:
|
||||||
"""Changes the virtual size of the image."""
|
"""Changes the virtual size of the image."""
|
||||||
cmd: Tuple[str, ...]
|
cmd: tuple[str, ...]
|
||||||
if file_format:
|
if file_format:
|
||||||
cmd = ('qemu-img', 'resize', '-f', file_format, source, '%sG' % size)
|
cmd = ('qemu-img', 'resize', '-f', file_format, source, '%sG' % size)
|
||||||
else:
|
else:
|
||||||
@ -922,7 +920,7 @@ def extract_targz(archive_name: str, target: str) -> None:
|
|||||||
utils.execute('tar', '-xzf', archive_name, '-C', target)
|
utils.execute('tar', '-xzf', archive_name, '-C', target)
|
||||||
|
|
||||||
|
|
||||||
def fix_vhd_chain(vhd_chain: List[str]) -> None:
|
def fix_vhd_chain(vhd_chain: list[str]) -> None:
|
||||||
for child, parent in zip(vhd_chain[:-1], vhd_chain[1:]):
|
for child, parent in zip(vhd_chain[:-1], vhd_chain[1:]):
|
||||||
set_vhd_parent(child, parent)
|
set_vhd_parent(child, parent)
|
||||||
|
|
||||||
@ -991,7 +989,7 @@ def temporary_dir() -> ContextManager[str]:
|
|||||||
return utils.tempdir(dir=CONF.image_conversion_dir)
|
return utils.tempdir(dir=CONF.image_conversion_dir)
|
||||||
|
|
||||||
|
|
||||||
def coalesce_chain(vhd_chain: List[str]) -> str:
|
def coalesce_chain(vhd_chain: list[str]) -> str:
|
||||||
for child, parent in zip(vhd_chain[:-1], vhd_chain[1:]):
|
for child, parent in zip(vhd_chain[:-1], vhd_chain[1:]):
|
||||||
with temporary_dir() as directory_for_journal:
|
with temporary_dir() as directory_for_journal:
|
||||||
size = get_vhd_size(child)
|
size = get_vhd_size(child)
|
||||||
@ -1003,7 +1001,7 @@ def coalesce_chain(vhd_chain: List[str]) -> str:
|
|||||||
return vhd_chain[-1]
|
return vhd_chain[-1]
|
||||||
|
|
||||||
|
|
||||||
def discover_vhd_chain(directory: str) -> List[str]:
|
def discover_vhd_chain(directory: str) -> list[str]:
|
||||||
counter = 0
|
counter = 0
|
||||||
chain = []
|
chain = []
|
||||||
|
|
||||||
@ -1028,7 +1026,7 @@ def replace_xenserver_image_with_coalesced_vhd(image_file: str) -> None:
|
|||||||
os.rename(coalesced, image_file)
|
os.rename(coalesced, image_file)
|
||||||
|
|
||||||
|
|
||||||
def decode_cipher(cipher_spec: str, key_size: int) -> Dict[str, str]:
|
def decode_cipher(cipher_spec: str, key_size: int) -> dict[str, str]:
|
||||||
"""Decode a dm-crypt style cipher specification string
|
"""Decode a dm-crypt style cipher specification string
|
||||||
|
|
||||||
The assumed format being cipher-chainmode-ivmode, similar to that
|
The assumed format being cipher-chainmode-ivmode, similar to that
|
||||||
@ -1060,7 +1058,7 @@ class TemporaryImages(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, image_service: glance.GlanceImageService):
|
def __init__(self, image_service: glance.GlanceImageService):
|
||||||
self.temporary_images: Dict[str, dict] = {}
|
self.temporary_images: dict[str, dict] = {}
|
||||||
self.image_service = image_service
|
self.image_service = image_service
|
||||||
image_service.temp_images = self
|
image_service.temp_images = self
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'init',
|
'init',
|
||||||
'cleanup',
|
'cleanup',
|
||||||
@ -26,7 +28,7 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
from typing import Tuple, Union # noqa: H301
|
from typing import Union
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -230,7 +232,7 @@ class RPCAPI(object):
|
|||||||
return versions[-1]
|
return versions[-1]
|
||||||
|
|
||||||
def _get_cctxt(self,
|
def _get_cctxt(self,
|
||||||
version: Union[str, Tuple[str, ...]] = None,
|
version: Union[str, tuple[str, ...]] = None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Prepare client context
|
"""Prepare client context
|
||||||
|
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
Pluggable Weighing support
|
Pluggable Weighing support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
from typing import Iterable, List, Optional # noqa: H301
|
from typing import Iterable, Optional # noqa: H301
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ from cinder.scheduler import base_handler
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def normalize(weight_list: List[float],
|
def normalize(weight_list: list[float],
|
||||||
minval: Optional[float] = None,
|
minval: Optional[float] = None,
|
||||||
maxval: Optional[float] = None) -> Iterable[float]:
|
maxval: Optional[float] = None) -> Iterable[float]:
|
||||||
"""Normalize the values in a list between 0 and 1.0.
|
"""Normalize the values in a list between 0 and 1.0.
|
||||||
@ -95,8 +97,8 @@ class BaseWeigher(object, metaclass=abc.ABCMeta):
|
|||||||
"""Override in a subclass to specify a weight for a specific object."""
|
"""Override in a subclass to specify a weight for a specific object."""
|
||||||
|
|
||||||
def weigh_objects(self,
|
def weigh_objects(self,
|
||||||
weighed_obj_list: List[WeighedObject],
|
weighed_obj_list: list[WeighedObject],
|
||||||
weight_properties: dict) -> List[float]:
|
weight_properties: dict) -> list[float]:
|
||||||
"""Weigh multiple objects.
|
"""Weigh multiple objects.
|
||||||
|
|
||||||
Override in a subclass if you need access to all objects in order
|
Override in a subclass if you need access to all objects in order
|
||||||
@ -130,8 +132,8 @@ class BaseWeightHandler(base_handler.BaseHandler):
|
|||||||
|
|
||||||
def get_weighed_objects(self,
|
def get_weighed_objects(self,
|
||||||
weigher_classes: list,
|
weigher_classes: list,
|
||||||
obj_list: List[WeighedObject],
|
obj_list: list[WeighedObject],
|
||||||
weighing_properties: dict) -> List[WeighedObject]:
|
weighing_properties: dict) -> list[WeighedObject]:
|
||||||
"""Return a sorted (descending), normalized list of WeighedObjects."""
|
"""Return a sorted (descending), normalized list of WeighedObjects."""
|
||||||
|
|
||||||
if not obj_list:
|
if not obj_list:
|
||||||
|
@ -13,9 +13,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
import operator
|
import operator
|
||||||
import re
|
import re
|
||||||
from typing import Callable, Dict # noqa: H301
|
from typing import Callable
|
||||||
|
|
||||||
import pyparsing
|
import pyparsing
|
||||||
|
|
||||||
@ -168,7 +170,7 @@ class EvalTernaryOp(object):
|
|||||||
|
|
||||||
|
|
||||||
class EvalFunction(object):
|
class EvalFunction(object):
|
||||||
functions: Dict[str, Callable] = {
|
functions: dict[str, Callable] = {
|
||||||
"abs": abs,
|
"abs": abs,
|
||||||
"max": max,
|
"max": max,
|
||||||
"min": min,
|
"min": min,
|
||||||
|
@ -20,7 +20,9 @@ You can customize this scheduler by specifying your own volume Filters and
|
|||||||
Weighing Functions.
|
Weighing Functions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List, Optional # noqa: H301
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -375,9 +377,9 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
|
|
||||||
def _get_weighted_candidates_generic_group(
|
def _get_weighted_candidates_generic_group(
|
||||||
self, context: context.RequestContext,
|
self, context: context.RequestContext,
|
||||||
group_spec: dict, request_spec_list: List[dict],
|
group_spec: dict, request_spec_list: list[dict],
|
||||||
group_filter_properties: Optional[dict] = None,
|
group_filter_properties: Optional[dict] = None,
|
||||||
filter_properties_list: Optional[List[dict]] = None) -> list:
|
filter_properties_list: Optional[list[dict]] = None) -> list:
|
||||||
"""Finds backends that supports the group.
|
"""Finds backends that supports the group.
|
||||||
|
|
||||||
Returns a list of backends that meet the required specs,
|
Returns a list of backends that meet the required specs,
|
||||||
@ -486,7 +488,7 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
def _get_weighted_candidates_by_group_type(
|
def _get_weighted_candidates_by_group_type(
|
||||||
self, context: context.RequestContext, group_spec: dict,
|
self, context: context.RequestContext, group_spec: dict,
|
||||||
group_filter_properties: Optional[dict] = None) \
|
group_filter_properties: Optional[dict] = None) \
|
||||||
-> List[WeighedHost]:
|
-> list[WeighedHost]:
|
||||||
"""Finds backends that supports the group type.
|
"""Finds backends that supports the group type.
|
||||||
|
|
||||||
Returns a list of backends that meet the required specs,
|
Returns a list of backends that meet the required specs,
|
||||||
@ -598,7 +600,7 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
return self._choose_top_backend_generic_group(weighed_backends)
|
return self._choose_top_backend_generic_group(weighed_backends)
|
||||||
|
|
||||||
def _choose_top_backend(self,
|
def _choose_top_backend(self,
|
||||||
weighed_backends: List[WeighedHost],
|
weighed_backends: list[WeighedHost],
|
||||||
request_spec: dict):
|
request_spec: dict):
|
||||||
top_backend = weighed_backends[0]
|
top_backend = weighed_backends[0]
|
||||||
backend_state = top_backend.obj
|
backend_state = top_backend.obj
|
||||||
@ -609,7 +611,7 @@ class FilterScheduler(driver.Scheduler):
|
|||||||
|
|
||||||
def _choose_top_backend_generic_group(
|
def _choose_top_backend_generic_group(
|
||||||
self,
|
self,
|
||||||
weighed_backends: List[WeighedHost]) -> WeighedHost:
|
weighed_backends: list[WeighedHost]) -> WeighedHost:
|
||||||
top_backend = weighed_backends[0]
|
top_backend = weighed_backends[0]
|
||||||
backend_state = top_backend.obj
|
backend_state = top_backend.obj
|
||||||
LOG.debug("Choosing %s", backend_state.backend_id)
|
LOG.debug("Choosing %s", backend_state.backend_id)
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from typing import Any, Dict, Optional # noqa: H301
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
|
from typing import Any, Optional # noqa: H301
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
@ -49,7 +51,7 @@ class ExtractSchedulerSpecTask(flow_utils.CinderTask):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
snapshot_id: Optional[str],
|
snapshot_id: Optional[str],
|
||||||
image_id: Optional[str],
|
image_id: Optional[str],
|
||||||
backup_id: Optional[str]) -> Dict[str, Any]:
|
backup_id: Optional[str]) -> dict[str, Any]:
|
||||||
# Create the full request spec using the volume object.
|
# Create the full request spec using the volume object.
|
||||||
#
|
#
|
||||||
# NOTE(dulek): At this point, a volume can be deleted before it gets
|
# NOTE(dulek): At this point, a volume can be deleted before it gets
|
||||||
@ -77,7 +79,7 @@ class ExtractSchedulerSpecTask(flow_utils.CinderTask):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
snapshot_id: Optional[str],
|
snapshot_id: Optional[str],
|
||||||
image_id: Optional[str],
|
image_id: Optional[str],
|
||||||
backup_id: Optional[str]) -> Dict[str, Any]:
|
backup_id: Optional[str]) -> dict[str, Any]:
|
||||||
# For RPC version < 1.2 backward compatibility
|
# For RPC version < 1.2 backward compatibility
|
||||||
if request_spec is None:
|
if request_spec is None:
|
||||||
request_spec = self._populate_request_spec(volume,
|
request_spec = self._populate_request_spec(volume,
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
|
|
||||||
"""Manage backends in the current zone."""
|
"""Manage backends in the current zone."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections import abc
|
from collections import abc
|
||||||
import random
|
import random
|
||||||
import typing
|
import typing
|
||||||
from typing import (Any, Dict, Iterable, List, # noqa: H301
|
from typing import (Any, Iterable, Optional, Type, Union) # noqa: H301
|
||||||
Optional, Type, Union)
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -163,7 +164,7 @@ class BackendState(object):
|
|||||||
self.service = ReadOnlyDict(service)
|
self.service = ReadOnlyDict(service)
|
||||||
|
|
||||||
def update_from_volume_capability(self,
|
def update_from_volume_capability(self,
|
||||||
capability: Dict[str, Any],
|
capability: dict[str, Any],
|
||||||
service=None) -> None:
|
service=None) -> None:
|
||||||
"""Update information about a host from its volume_node info.
|
"""Update information about a host from its volume_node info.
|
||||||
|
|
||||||
@ -289,7 +290,7 @@ class BackendState(object):
|
|||||||
'host': self.host})
|
'host': self.host})
|
||||||
del self.pools[pool]
|
del self.pools[pool]
|
||||||
|
|
||||||
def _append_backend_info(self, pool_cap: Dict[str, Any]) -> None:
|
def _append_backend_info(self, pool_cap: dict[str, Any]) -> None:
|
||||||
# Fill backend level info to pool if needed.
|
# Fill backend level info to pool if needed.
|
||||||
if not pool_cap.get('volume_backend_name', None):
|
if not pool_cap.get('volume_backend_name', None):
|
||||||
pool_cap['volume_backend_name'] = self.volume_backend_name
|
pool_cap['volume_backend_name'] = self.volume_backend_name
|
||||||
@ -407,7 +408,7 @@ class PoolState(BackendState):
|
|||||||
self.pools: dict = {}
|
self.pools: dict = {}
|
||||||
|
|
||||||
def update_from_volume_capability(self,
|
def update_from_volume_capability(self,
|
||||||
capability: Dict[str, Any],
|
capability: dict[str, Any],
|
||||||
service=None) -> None:
|
service=None) -> None:
|
||||||
"""Update information about a pool from its volume_node info."""
|
"""Update information about a pool from its volume_node info."""
|
||||||
LOG.debug("Updating capabilities for %s: %s", self.host, capability)
|
LOG.debug("Updating capabilities for %s: %s", self.host, capability)
|
||||||
@ -470,7 +471,7 @@ class HostManager(object):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.service_states = {} # { <host|cluster>: {<service>: {cap k : v}}}
|
self.service_states = {} # { <host|cluster>: {<service>: {cap k : v}}}
|
||||||
self.backend_state_map: Dict[str, BackendState] = {}
|
self.backend_state_map: dict[str, BackendState] = {}
|
||||||
self.backup_service_states = {}
|
self.backup_service_states = {}
|
||||||
self.filter_handler = filters.BackendFilterHandler('cinder.scheduler.'
|
self.filter_handler = filters.BackendFilterHandler('cinder.scheduler.'
|
||||||
'filters')
|
'filters')
|
||||||
@ -513,7 +514,7 @@ class HostManager(object):
|
|||||||
|
|
||||||
def _choose_backend_weighers(
|
def _choose_backend_weighers(
|
||||||
self,
|
self,
|
||||||
weight_cls_names: Optional[List[str]]) -> list:
|
weight_cls_names: Optional[list[str]]) -> list:
|
||||||
"""Return a list of available weigher names.
|
"""Return a list of available weigher names.
|
||||||
|
|
||||||
This function checks input weigher names against a predefined set
|
This function checks input weigher names against a predefined set
|
||||||
@ -795,7 +796,7 @@ class HostManager(object):
|
|||||||
|
|
||||||
def get_pools(self,
|
def get_pools(self,
|
||||||
context: cinder_context.RequestContext,
|
context: cinder_context.RequestContext,
|
||||||
filters: Optional[dict] = None) -> List[dict]:
|
filters: Optional[dict] = None) -> list[dict]:
|
||||||
"""Returns a dict of all pools on all hosts HostManager knows about."""
|
"""Returns a dict of all pools on all hosts HostManager knows about."""
|
||||||
|
|
||||||
self._update_backend_state_map(context)
|
self._update_backend_state_map(context)
|
||||||
@ -858,7 +859,7 @@ class HostManager(object):
|
|||||||
capa_new: dict,
|
capa_new: dict,
|
||||||
updated_pools: Iterable[dict],
|
updated_pools: Iterable[dict],
|
||||||
host: str,
|
host: str,
|
||||||
timestamp) -> List[dict]:
|
timestamp) -> list[dict]:
|
||||||
pools = capa_new.get('pools')
|
pools = capa_new.get('pools')
|
||||||
usage = []
|
usage = []
|
||||||
if pools and isinstance(pools, list):
|
if pools and isinstance(pools, list):
|
||||||
@ -888,7 +889,7 @@ class HostManager(object):
|
|||||||
|
|
||||||
def _get_pool_usage(self,
|
def _get_pool_usage(self,
|
||||||
pool: dict,
|
pool: dict,
|
||||||
host: str, timestamp) -> Dict[str, Any]:
|
host: str, timestamp) -> dict[str, Any]:
|
||||||
total = pool["total_capacity_gb"]
|
total = pool["total_capacity_gb"]
|
||||||
free = pool["free_capacity_gb"]
|
free = pool["free_capacity_gb"]
|
||||||
|
|
||||||
@ -967,7 +968,7 @@ class HostManager(object):
|
|||||||
|
|
||||||
def _notify_capacity_usage(self,
|
def _notify_capacity_usage(self,
|
||||||
context: cinder_context.RequestContext,
|
context: cinder_context.RequestContext,
|
||||||
usage: List[dict]) -> None:
|
usage: list[dict]) -> None:
|
||||||
if usage:
|
if usage:
|
||||||
for u in usage:
|
for u in usage:
|
||||||
volume_utils.notify_about_capacity_usage(
|
volume_utils.notify_about_capacity_usage(
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
should be placed in volume_utils instead.
|
should be placed in volume_utils instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import contextlib
|
import contextlib
|
||||||
import datetime
|
import datetime
|
||||||
@ -42,8 +44,8 @@ import stat
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import typing
|
import typing
|
||||||
from typing import Callable, Dict, Iterable, Iterator, List # noqa: H301
|
from typing import Callable, Iterable, Iterator # noqa: H301
|
||||||
from typing import Optional, Tuple, Type, Union # noqa: H301
|
from typing import Optional, Type, Union # noqa: H301
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import tpool
|
from eventlet import tpool
|
||||||
@ -165,15 +167,15 @@ def check_exclusive_options(
|
|||||||
raise exception.InvalidInput(reason=msg)
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
|
||||||
def execute(*cmd: str, **kwargs: Union[bool, str]) -> Tuple[str, str]:
|
def execute(*cmd: str, **kwargs: Union[bool, str]) -> tuple[str, str]:
|
||||||
"""Convenience wrapper around oslo's execute() method."""
|
"""Convenience wrapper around oslo's execute() method."""
|
||||||
if 'run_as_root' in kwargs and 'root_helper' not in kwargs:
|
if 'run_as_root' in kwargs and 'root_helper' not in kwargs:
|
||||||
kwargs['root_helper'] = get_root_helper()
|
kwargs['root_helper'] = get_root_helper()
|
||||||
return processutils.execute(*cmd, **kwargs)
|
return processutils.execute(*cmd, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def check_ssh_injection(cmd_list: List[str]) -> None:
|
def check_ssh_injection(cmd_list: list[str]) -> None:
|
||||||
ssh_injection_pattern: Tuple[str, ...] = ('`', '$', '|', '||', ';', '&',
|
ssh_injection_pattern: tuple[str, ...] = ('`', '$', '|', '||', ';', '&',
|
||||||
'&&', '>', '>>', '<')
|
'&&', '>', '>>', '<')
|
||||||
|
|
||||||
# Check whether injection attacks exist
|
# Check whether injection attacks exist
|
||||||
@ -208,7 +210,7 @@ def check_ssh_injection(cmd_list: List[str]) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def check_metadata_properties(
|
def check_metadata_properties(
|
||||||
metadata: Optional[Dict[str, str]]) -> None:
|
metadata: Optional[dict[str, str]]) -> None:
|
||||||
"""Checks that the volume metadata properties are valid."""
|
"""Checks that the volume metadata properties are valid."""
|
||||||
|
|
||||||
if not metadata:
|
if not metadata:
|
||||||
@ -235,7 +237,7 @@ def check_metadata_properties(
|
|||||||
|
|
||||||
|
|
||||||
def last_completed_audit_period(unit: Optional[str] = None) -> \
|
def last_completed_audit_period(unit: Optional[str] = None) -> \
|
||||||
Tuple[Union[datetime.datetime, datetime.timedelta],
|
tuple[Union[datetime.datetime, datetime.timedelta],
|
||||||
Union[datetime.datetime, datetime.timedelta]]:
|
Union[datetime.datetime, datetime.timedelta]]:
|
||||||
"""This method gives you the most recently *completed* audit period.
|
"""This method gives you the most recently *completed* audit period.
|
||||||
|
|
||||||
@ -496,7 +498,7 @@ def get_file_size(path: str) -> int:
|
|||||||
|
|
||||||
def _get_disk_of_partition(
|
def _get_disk_of_partition(
|
||||||
devpath: str,
|
devpath: str,
|
||||||
st: Optional[os.stat_result] = None) -> Tuple[str, os.stat_result]:
|
st: Optional[os.stat_result] = None) -> tuple[str, os.stat_result]:
|
||||||
"""Gets a disk device path and status from partition path.
|
"""Gets a disk device path and status from partition path.
|
||||||
|
|
||||||
Returns a disk device path from a partition device path, and stat for
|
Returns a disk device path from a partition device path, and stat for
|
||||||
@ -633,9 +635,9 @@ class retry_if_exit_code(tenacity.retry_if_exception):
|
|||||||
|
|
||||||
def retry(retry_param: Union[None,
|
def retry(retry_param: Union[None,
|
||||||
Type[Exception],
|
Type[Exception],
|
||||||
Tuple[Type[Exception], ...],
|
tuple[Type[Exception], ...],
|
||||||
int,
|
int,
|
||||||
Tuple[int, ...]],
|
tuple[int, ...]],
|
||||||
interval: float = 1,
|
interval: float = 1,
|
||||||
retries: int = 3,
|
retries: int = 3,
|
||||||
backoff_rate: float = 2,
|
backoff_rate: float = 2,
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
"""Handles all requests relating to volumes."""
|
"""Handles all requests relating to volumes."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import collections
|
import collections
|
||||||
import datetime
|
import datetime
|
||||||
from typing import (Any, DefaultDict, Dict, Iterable, List, # noqa: H301
|
from typing import (Any, DefaultDict, Iterable, Optional, Union) # noqa: H301
|
||||||
Optional, Tuple, Union)
|
|
||||||
|
|
||||||
from castellan import key_manager
|
from castellan import key_manager
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -139,7 +140,7 @@ class API(base.Base):
|
|||||||
services = objects.ServiceList.get_all_by_topic(ctxt, topic)
|
services = objects.ServiceList.get_all_by_topic(ctxt, topic)
|
||||||
az_data = [(s.availability_zone, s.disabled)
|
az_data = [(s.availability_zone, s.disabled)
|
||||||
for s in services]
|
for s in services]
|
||||||
disabled_map: Dict[str, bool] = {}
|
disabled_map: dict[str, bool] = {}
|
||||||
for (az_name, disabled) in az_data:
|
for (az_name, disabled) in az_data:
|
||||||
tracked_disabled = disabled_map.get(az_name, True)
|
tracked_disabled = disabled_map.get(az_name, True)
|
||||||
disabled_map[az_name] = tracked_disabled and disabled
|
disabled_map[az_name] = tracked_disabled and disabled
|
||||||
@ -725,8 +726,8 @@ class API(base.Base):
|
|||||||
search_opts: Optional[dict] = None,
|
search_opts: Optional[dict] = None,
|
||||||
marker: Optional[str] = None,
|
marker: Optional[str] = None,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
sort_keys: Optional[List[str]] = None,
|
sort_keys: Optional[list[str]] = None,
|
||||||
sort_dirs: Optional[List[str]] = None,
|
sort_dirs: Optional[list[str]] = None,
|
||||||
offset: Optional[int] = None) -> objects.SnapshotList:
|
offset: Optional[int] = None) -> objects.SnapshotList:
|
||||||
context.authorize(snapshot_policy.GET_ALL_POLICY)
|
context.authorize(snapshot_policy.GET_ALL_POLICY)
|
||||||
|
|
||||||
@ -971,7 +972,7 @@ class API(base.Base):
|
|||||||
|
|
||||||
utils.check_metadata_properties(metadata)
|
utils.check_metadata_properties(metadata)
|
||||||
|
|
||||||
valid_status: Tuple[str, ...]
|
valid_status: tuple[str, ...]
|
||||||
valid_status = ('available',)
|
valid_status = ('available',)
|
||||||
if force or allow_in_use:
|
if force or allow_in_use:
|
||||||
valid_status = ('available', 'in-use')
|
valid_status = ('available', 'in-use')
|
||||||
@ -1118,7 +1119,7 @@ class API(base.Base):
|
|||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume_list: objects.VolumeList) -> list:
|
volume_list: objects.VolumeList) -> list:
|
||||||
reserve_opts_list = []
|
reserve_opts_list = []
|
||||||
total_reserve_opts: Dict[str, int] = {}
|
total_reserve_opts: dict[str, int] = {}
|
||||||
try:
|
try:
|
||||||
for volume in volume_list:
|
for volume in volume_list:
|
||||||
if CONF.no_snapshot_gb_quota:
|
if CONF.no_snapshot_gb_quota:
|
||||||
@ -1155,7 +1156,7 @@ class API(base.Base):
|
|||||||
name: str,
|
name: str,
|
||||||
description: str,
|
description: str,
|
||||||
cgsnapshot_id: str,
|
cgsnapshot_id: str,
|
||||||
group_snapshot_id: Optional[str] = None) -> Dict[str, Any]:
|
group_snapshot_id: Optional[str] = None) -> dict[str, Any]:
|
||||||
options = {'volume_id': volume['id'],
|
options = {'volume_id': volume['id'],
|
||||||
'cgsnapshot_id': cgsnapshot_id,
|
'cgsnapshot_id': cgsnapshot_id,
|
||||||
'group_snapshot_id': group_snapshot_id,
|
'group_snapshot_id': group_snapshot_id,
|
||||||
@ -1176,7 +1177,7 @@ class API(base.Base):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
name: str,
|
name: str,
|
||||||
description: str,
|
description: str,
|
||||||
metadata: Optional[Dict[str, Any]] = None,
|
metadata: Optional[dict[str, Any]] = None,
|
||||||
cgsnapshot_id: Optional[str] = None,
|
cgsnapshot_id: Optional[str] = None,
|
||||||
group_snapshot_id: Optional[str] = None,
|
group_snapshot_id: Optional[str] = None,
|
||||||
allow_in_use: bool = False) -> objects.Snapshot:
|
allow_in_use: bool = False) -> objects.Snapshot:
|
||||||
@ -1193,7 +1194,7 @@ class API(base.Base):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
name: str,
|
name: str,
|
||||||
description: str,
|
description: str,
|
||||||
metadata: Optional[Dict[str, Any]] = None) -> objects.Snapshot:
|
metadata: Optional[dict[str, Any]] = None) -> objects.Snapshot:
|
||||||
result = self._create_snapshot(context, volume, name, description,
|
result = self._create_snapshot(context, volume, name, description,
|
||||||
True, metadata)
|
True, metadata)
|
||||||
LOG.info("Snapshot force create request issued successfully.",
|
LOG.info("Snapshot force create request issued successfully.",
|
||||||
@ -1211,7 +1212,7 @@ class API(base.Base):
|
|||||||
snapshot.assert_not_frozen()
|
snapshot.assert_not_frozen()
|
||||||
|
|
||||||
# Build required conditions for conditional update
|
# Build required conditions for conditional update
|
||||||
expected: Dict[str, Any] = {'cgsnapshot_id': None,
|
expected: dict[str, Any] = {'cgsnapshot_id': None,
|
||||||
'group_snapshot_id': None}
|
'group_snapshot_id': None}
|
||||||
# If not force deleting we have status conditions
|
# If not force deleting we have status conditions
|
||||||
if not force:
|
if not force:
|
||||||
@ -1237,7 +1238,7 @@ class API(base.Base):
|
|||||||
def update_snapshot(self,
|
def update_snapshot(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
snapshot: objects.Snapshot,
|
snapshot: objects.Snapshot,
|
||||||
fields: Dict[str, Any]) -> None:
|
fields: dict[str, Any]) -> None:
|
||||||
context.authorize(snapshot_policy.UPDATE_POLICY,
|
context.authorize(snapshot_policy.UPDATE_POLICY,
|
||||||
target_obj=snapshot)
|
target_obj=snapshot)
|
||||||
snapshot.update(fields)
|
snapshot.update(fields)
|
||||||
@ -1256,7 +1257,7 @@ class API(base.Base):
|
|||||||
def create_volume_metadata(self,
|
def create_volume_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
metadata: Dict[str, Any]) -> dict:
|
metadata: dict[str, Any]) -> dict:
|
||||||
"""Creates volume metadata."""
|
"""Creates volume metadata."""
|
||||||
context.authorize(vol_meta_policy.CREATE_POLICY, target_obj=volume)
|
context.authorize(vol_meta_policy.CREATE_POLICY, target_obj=volume)
|
||||||
db_meta = self._update_volume_metadata(context, volume, metadata)
|
db_meta = self._update_volume_metadata(context, volume, metadata)
|
||||||
@ -1284,7 +1285,7 @@ class API(base.Base):
|
|||||||
def _update_volume_metadata(self,
|
def _update_volume_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
metadata: Dict[str, Any],
|
metadata: dict[str, Any],
|
||||||
delete: bool = False,
|
delete: bool = False,
|
||||||
meta_type=common.METADATA_TYPES.user) -> dict:
|
meta_type=common.METADATA_TYPES.user) -> dict:
|
||||||
if volume['status'] in ('maintenance', 'uploading'):
|
if volume['status'] in ('maintenance', 'uploading'):
|
||||||
@ -1298,7 +1299,7 @@ class API(base.Base):
|
|||||||
def update_volume_metadata(self,
|
def update_volume_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
metadata: Dict[str, Any],
|
metadata: dict[str, Any],
|
||||||
delete: bool = False,
|
delete: bool = False,
|
||||||
meta_type=common.METADATA_TYPES.user) -> dict:
|
meta_type=common.METADATA_TYPES.user) -> dict:
|
||||||
"""Updates volume metadata.
|
"""Updates volume metadata.
|
||||||
@ -1320,7 +1321,7 @@ class API(base.Base):
|
|||||||
def update_volume_admin_metadata(self,
|
def update_volume_admin_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
metadata: Dict[str, Any],
|
metadata: dict[str, Any],
|
||||||
delete: Optional[bool] = False,
|
delete: Optional[bool] = False,
|
||||||
add: Optional[bool] = True,
|
add: Optional[bool] = True,
|
||||||
update: Optional[bool] = True) -> dict:
|
update: Optional[bool] = True) -> dict:
|
||||||
@ -1369,7 +1370,7 @@ class API(base.Base):
|
|||||||
def update_snapshot_metadata(self,
|
def update_snapshot_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
snapshot: objects.Snapshot,
|
snapshot: objects.Snapshot,
|
||||||
metadata: Dict[str, Any],
|
metadata: dict[str, Any],
|
||||||
delete: bool = False) -> dict:
|
delete: bool = False) -> dict:
|
||||||
"""Updates or creates snapshot metadata.
|
"""Updates or creates snapshot metadata.
|
||||||
|
|
||||||
@ -1410,7 +1411,7 @@ class API(base.Base):
|
|||||||
|
|
||||||
def get_volume_image_metadata(self,
|
def get_volume_image_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume) -> Dict[str, str]:
|
volume: objects.Volume) -> dict[str, str]:
|
||||||
context.authorize(vol_meta_policy.GET_POLICY, target_obj=volume)
|
context.authorize(vol_meta_policy.GET_POLICY, target_obj=volume)
|
||||||
db_data = self.db.volume_glance_metadata_get(context, volume['id'])
|
db_data = self.db.volume_glance_metadata_get(context, volume['id'])
|
||||||
LOG.info("Get volume image-metadata completed successfully.",
|
LOG.info("Get volume image-metadata completed successfully.",
|
||||||
@ -1420,7 +1421,7 @@ class API(base.Base):
|
|||||||
def get_list_volumes_image_metadata(
|
def get_list_volumes_image_metadata(
|
||||||
self,
|
self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume_id_list: List[str]) -> DefaultDict[str, str]:
|
volume_id_list: list[str]) -> DefaultDict[str, str]:
|
||||||
db_data = self.db.volume_glance_metadata_list_get(context,
|
db_data = self.db.volume_glance_metadata_list_get(context,
|
||||||
volume_id_list)
|
volume_id_list)
|
||||||
results: collections.defaultdict = collections.defaultdict(dict)
|
results: collections.defaultdict = collections.defaultdict(dict)
|
||||||
@ -1458,8 +1459,8 @@ class API(base.Base):
|
|||||||
def copy_volume_to_image(self,
|
def copy_volume_to_image(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
metadata: Dict[str, str],
|
metadata: dict[str, str],
|
||||||
force: bool) -> Dict[str, Optional[str]]:
|
force: bool) -> dict[str, Optional[str]]:
|
||||||
"""Create a new image from the specified volume."""
|
"""Create a new image from the specified volume."""
|
||||||
if not CONF.enable_force_upload and force:
|
if not CONF.enable_force_upload and force:
|
||||||
LOG.info("Force upload to image is disabled, "
|
LOG.info("Force upload to image is disabled, "
|
||||||
@ -2069,8 +2070,8 @@ class API(base.Base):
|
|||||||
marker: Optional[str] = None,
|
marker: Optional[str] = None,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
offset: Optional[int] = None,
|
offset: Optional[int] = None,
|
||||||
sort_keys: Optional[List[str]] = None,
|
sort_keys: Optional[list[str]] = None,
|
||||||
sort_dirs: Optional[List[str]] = None):
|
sort_dirs: Optional[list[str]] = None):
|
||||||
svc = self._get_service_by_host_cluster(context, host, cluster_name)
|
svc = self._get_service_by_host_cluster(context, host, cluster_name)
|
||||||
return self.volume_rpcapi.get_manageable_volumes(context, svc,
|
return self.volume_rpcapi.get_manageable_volumes(context, svc,
|
||||||
marker, limit,
|
marker, limit,
|
||||||
@ -2110,8 +2111,8 @@ class API(base.Base):
|
|||||||
marker: Optional[str] = None,
|
marker: Optional[str] = None,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
offset: Optional[int] = None,
|
offset: Optional[int] = None,
|
||||||
sort_keys: Optional[List[str]] = None,
|
sort_keys: Optional[list[str]] = None,
|
||||||
sort_dirs: Optional[List[str]] = None) -> List[dict]:
|
sort_dirs: Optional[list[str]] = None) -> list[dict]:
|
||||||
svc = self._get_service_by_host_cluster(context, host, cluster_name,
|
svc = self._get_service_by_host_cluster(context, host, cluster_name,
|
||||||
'snapshot')
|
'snapshot')
|
||||||
return self.volume_rpcapi.get_manageable_snapshots(context, svc,
|
return self.volume_rpcapi.get_manageable_snapshots(context, svc,
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
"""RADOS Block Device Driver"""
|
"""RADOS Block Device Driver"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import errno
|
import errno
|
||||||
import json
|
import json
|
||||||
@ -20,7 +22,7 @@ import math
|
|||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Dict, List, Optional, Tuple, Union # noqa: H301
|
from typing import Any, Optional, Union # noqa: H301
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
from castellan import key_manager
|
from castellan import key_manager
|
||||||
@ -163,7 +165,7 @@ class RBDVolumeProxy(object):
|
|||||||
pool: Optional[str] = None,
|
pool: Optional[str] = None,
|
||||||
snapshot: Optional[str] = None,
|
snapshot: Optional[str] = None,
|
||||||
read_only: bool = False,
|
read_only: bool = False,
|
||||||
remote: Optional[Dict[str, str]] = None,
|
remote: Optional[dict[str, str]] = None,
|
||||||
timeout: Optional[int] = None,
|
timeout: Optional[int] = None,
|
||||||
client: 'rados.Rados' = None,
|
client: 'rados.Rados' = None,
|
||||||
ioctx: 'rados.Ioctx' = None):
|
ioctx: 'rados.Ioctx' = None):
|
||||||
@ -254,7 +256,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
**kwargs) -> None:
|
**kwargs) -> None:
|
||||||
super(RBDDriver, self).__init__(*args, **kwargs)
|
super(RBDDriver, self).__init__(*args, **kwargs)
|
||||||
self.configuration.append_config_values(RBD_OPTS)
|
self.configuration.append_config_values(RBD_OPTS)
|
||||||
self._stats: Dict[str, Union[str, bool]] = {}
|
self._stats: dict[str, Union[str, bool]] = {}
|
||||||
# allow overrides for testing
|
# allow overrides for testing
|
||||||
self.rados = kwargs.get('rados', rados)
|
self.rados = kwargs.get('rados', rados)
|
||||||
self.rbd = kwargs.get('rbd', rbd)
|
self.rbd = kwargs.get('rbd', rbd)
|
||||||
@ -270,10 +272,10 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
self._backend_name = (self.configuration.volume_backend_name or
|
self._backend_name = (self.configuration.volume_backend_name or
|
||||||
self.__class__.__name__)
|
self.__class__.__name__)
|
||||||
self._active_backend_id: Optional[str] = active_backend_id
|
self._active_backend_id: Optional[str] = active_backend_id
|
||||||
self._active_config: Dict[str, str] = {}
|
self._active_config: dict[str, str] = {}
|
||||||
self._is_replication_enabled = False
|
self._is_replication_enabled = False
|
||||||
self._replication_targets: list = []
|
self._replication_targets: list = []
|
||||||
self._target_names: List[str] = []
|
self._target_names: list[str] = []
|
||||||
self._clone_v2_api_checked: bool = False
|
self._clone_v2_api_checked: bool = False
|
||||||
|
|
||||||
if self.rbd is not None:
|
if self.rbd is not None:
|
||||||
@ -341,7 +343,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
' performance, fewer deletion issues')
|
' performance, fewer deletion issues')
|
||||||
|
|
||||||
def _get_target_config(self,
|
def _get_target_config(self,
|
||||||
target_id: Optional[str]) -> Dict[str,
|
target_id: Optional[str]) -> dict[str,
|
||||||
str]:
|
str]:
|
||||||
"""Get a replication target from known replication targets."""
|
"""Get a replication target from known replication targets."""
|
||||||
for target in self._replication_targets:
|
for target in self._replication_targets:
|
||||||
@ -371,7 +373,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
self._target_names.append('default')
|
self._target_names.append('default')
|
||||||
|
|
||||||
def _parse_replication_configs(self,
|
def _parse_replication_configs(self,
|
||||||
replication_devices: List[dict]) -> None:
|
replication_devices: list[dict]) -> None:
|
||||||
for replication_device in replication_devices:
|
for replication_device in replication_devices:
|
||||||
if 'backend_id' not in replication_device:
|
if 'backend_id' not in replication_device:
|
||||||
msg = _('Missing backend_id in replication_device '
|
msg = _('Missing backend_id in replication_device '
|
||||||
@ -396,8 +398,8 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def _get_config_tuple(
|
def _get_config_tuple(
|
||||||
self,
|
self,
|
||||||
remote: Optional[Dict[str, str]] = None) \
|
remote: Optional[dict[str, str]] = None) \
|
||||||
-> Tuple[Optional[str], Optional[str],
|
-> tuple[Optional[str], Optional[str],
|
||||||
Optional[str], Optional[str]]:
|
Optional[str], Optional[str]]:
|
||||||
if not remote:
|
if not remote:
|
||||||
remote = self._active_config
|
remote = self._active_config
|
||||||
@ -486,7 +488,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
def RBDProxy(self) -> tpool.Proxy:
|
def RBDProxy(self) -> tpool.Proxy:
|
||||||
return tpool.Proxy(self.rbd.RBD())
|
return tpool.Proxy(self.rbd.RBD())
|
||||||
|
|
||||||
def _ceph_args(self) -> List[str]:
|
def _ceph_args(self) -> list[str]:
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
name, conf, user, secret_uuid = self._get_config_tuple()
|
name, conf, user, secret_uuid = self._get_config_tuple()
|
||||||
@ -504,13 +506,13 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
pool: Optional[str] = None,
|
pool: Optional[str] = None,
|
||||||
remote: Optional[dict] = None,
|
remote: Optional[dict] = None,
|
||||||
timeout: Optional[int] = None) -> \
|
timeout: Optional[int] = None) -> \
|
||||||
Tuple['rados.Rados', 'rados.Ioctx']:
|
tuple['rados.Rados', 'rados.Ioctx']:
|
||||||
@utils.retry(exception.VolumeBackendAPIException,
|
@utils.retry(exception.VolumeBackendAPIException,
|
||||||
self.configuration.rados_connection_interval,
|
self.configuration.rados_connection_interval,
|
||||||
self.configuration.rados_connection_retries)
|
self.configuration.rados_connection_retries)
|
||||||
def _do_conn(pool: Optional[str],
|
def _do_conn(pool: Optional[str],
|
||||||
remote: Optional[dict],
|
remote: Optional[dict],
|
||||||
timeout: Optional[int]) -> Tuple['rados.Rados',
|
timeout: Optional[int]) -> tuple['rados.Rados',
|
||||||
'rados.Ioctx']:
|
'rados.Ioctx']:
|
||||||
name, conf, user, secret_uuid = self._get_config_tuple(remote)
|
name, conf, user, secret_uuid = self._get_config_tuple(remote)
|
||||||
|
|
||||||
@ -557,7 +559,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
client.shutdown()
|
client.shutdown()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_backup_snaps(rbd_image) -> List:
|
def _get_backup_snaps(rbd_image) -> list:
|
||||||
"""Get list of any backup snapshots that exist on this volume.
|
"""Get list of any backup snapshots that exist on this volume.
|
||||||
|
|
||||||
There should only ever be one but accept all since they need to be
|
There should only ever be one but accept all since they need to be
|
||||||
@ -570,7 +572,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
from cinder.backup.drivers import ceph
|
from cinder.backup.drivers import ceph
|
||||||
return ceph.CephBackupDriver.get_backup_snaps(rbd_image)
|
return ceph.CephBackupDriver.get_backup_snaps(rbd_image)
|
||||||
|
|
||||||
def _get_mon_addrs(self) -> Tuple[List[str], List[str]]:
|
def _get_mon_addrs(self) -> tuple[list[str], list[str]]:
|
||||||
args = ['ceph', 'mon', 'dump', '--format=json']
|
args = ['ceph', 'mon', 'dump', '--format=json']
|
||||||
args.extend(self._ceph_args())
|
args.extend(self._ceph_args())
|
||||||
out, _ = self._execute(*args)
|
out, _ = self._execute(*args)
|
||||||
@ -578,7 +580,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
if lines[0].startswith('dumped monmap epoch'):
|
if lines[0].startswith('dumped monmap epoch'):
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
monmap = json.loads('\n'.join(lines))
|
monmap = json.loads('\n'.join(lines))
|
||||||
addrs: List[str] = [mon['addr'] for mon in monmap['mons']]
|
addrs: list[str] = [mon['addr'] for mon in monmap['mons']]
|
||||||
hosts = []
|
hosts = []
|
||||||
ports = []
|
ports = []
|
||||||
for addr in addrs:
|
for addr in addrs:
|
||||||
@ -614,8 +616,8 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
total_provisioned = math.ceil(float(total_provisioned) / units.Gi)
|
total_provisioned = math.ceil(float(total_provisioned) / units.Gi)
|
||||||
return total_provisioned
|
return total_provisioned
|
||||||
|
|
||||||
def _get_pool_stats(self) -> Union[Tuple[str, str],
|
def _get_pool_stats(self) -> Union[tuple[str, str],
|
||||||
Tuple[float, float]]:
|
tuple[float, float]]:
|
||||||
"""Gets pool free and total capacity in GiB.
|
"""Gets pool free and total capacity in GiB.
|
||||||
|
|
||||||
Calculate free and total capacity of the pool based on the pool's
|
Calculate free and total capacity of the pool based on the pool's
|
||||||
@ -753,7 +755,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
def create_cloned_volume(
|
def create_cloned_volume(
|
||||||
self,
|
self,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
src_vref: Volume) -> Optional[Dict[str, Optional[str]]]:
|
src_vref: Volume) -> Optional[dict[str, Optional[str]]]:
|
||||||
"""Create a cloned volume from another volume.
|
"""Create a cloned volume from another volume.
|
||||||
|
|
||||||
Since we are cloning from a volume and not a snapshot, we must first
|
Since we are cloning from a volume and not a snapshot, we must first
|
||||||
@ -860,7 +862,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
LOG.debug("clone created successfully")
|
LOG.debug("clone created successfully")
|
||||||
return volume_update
|
return volume_update
|
||||||
|
|
||||||
def _enable_replication(self, volume: Volume) -> Dict[str, str]:
|
def _enable_replication(self, volume: Volume) -> dict[str, str]:
|
||||||
"""Enable replication for a volume.
|
"""Enable replication for a volume.
|
||||||
|
|
||||||
Returns required volume update.
|
Returns required volume update.
|
||||||
@ -884,7 +886,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
return {'replication_status': fields.ReplicationStatus.ENABLED,
|
return {'replication_status': fields.ReplicationStatus.ENABLED,
|
||||||
'replication_driver_data': driver_data}
|
'replication_driver_data': driver_data}
|
||||||
|
|
||||||
def _enable_multiattach(self, volume: Volume) -> Dict[str, str]:
|
def _enable_multiattach(self, volume: Volume) -> dict[str, str]:
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
with RBDVolumeProxy(self, vol_name) as image:
|
with RBDVolumeProxy(self, vol_name) as image:
|
||||||
image_features = image.features()
|
image_features = image.features()
|
||||||
@ -894,7 +896,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
return {'provider_location':
|
return {'provider_location':
|
||||||
self._dumps({'saved_features': image_features})}
|
self._dumps({'saved_features': image_features})}
|
||||||
|
|
||||||
def _disable_multiattach(self, volume: Volume) -> Dict[str, None]:
|
def _disable_multiattach(self, volume: Volume) -> dict[str, None]:
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
with RBDVolumeProxy(self, vol_name) as image:
|
with RBDVolumeProxy(self, vol_name) as image:
|
||||||
try:
|
try:
|
||||||
@ -932,7 +934,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
def _setup_volume(
|
def _setup_volume(
|
||||||
self,
|
self,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
volume_type: Optional[VolumeType] = None) -> Dict[str,
|
volume_type: Optional[VolumeType] = None) -> dict[str,
|
||||||
Optional[str]]:
|
Optional[str]]:
|
||||||
|
|
||||||
if volume_type:
|
if volume_type:
|
||||||
@ -1030,7 +1032,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
cmd.extend(self._ceph_args())
|
cmd.extend(self._ceph_args())
|
||||||
self._execute(*cmd)
|
self._execute(*cmd)
|
||||||
|
|
||||||
def create_volume(self, volume: Volume) -> Dict[str, Any]:
|
def create_volume(self, volume: Volume) -> dict[str, Any]:
|
||||||
"""Creates a logical volume."""
|
"""Creates a logical volume."""
|
||||||
|
|
||||||
if volume.encryption_key_id:
|
if volume.encryption_key_id:
|
||||||
@ -1092,7 +1094,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
volume: Volume,
|
volume: Volume,
|
||||||
src_pool: str,
|
src_pool: str,
|
||||||
src_image: str,
|
src_image: str,
|
||||||
src_snap: str) -> Dict[str, Optional[str]]:
|
src_snap: str) -> dict[str, Optional[str]]:
|
||||||
LOG.debug('cloning %(pool)s/%(img)s@%(snap)s to %(dst)s',
|
LOG.debug('cloning %(pool)s/%(img)s@%(snap)s to %(dst)s',
|
||||||
dict(pool=src_pool, img=src_image, snap=src_snap,
|
dict(pool=src_pool, img=src_image, snap=src_snap,
|
||||||
dst=volume.name))
|
dst=volume.name))
|
||||||
@ -1178,8 +1180,8 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
self,
|
self,
|
||||||
volume: 'rbd.Image',
|
volume: 'rbd.Image',
|
||||||
volume_name: str,
|
volume_name: str,
|
||||||
snap: Optional[str] = None) -> Union[Tuple[str, str, str],
|
snap: Optional[str] = None) -> Union[tuple[str, str, str],
|
||||||
Tuple[None, None, None]]:
|
tuple[None, None, None]]:
|
||||||
"""If volume is a clone, return its parent info.
|
"""If volume is a clone, return its parent info.
|
||||||
|
|
||||||
Returns a tuple of (pool, parent, snap). A snapshot may optionally be
|
Returns a tuple of (pool, parent, snap). A snapshot may optionally be
|
||||||
@ -1207,7 +1209,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def _get_children_info(self,
|
def _get_children_info(self,
|
||||||
volume: 'rbd.Image',
|
volume: 'rbd.Image',
|
||||||
snap: Optional[str]) -> List[tuple]:
|
snap: Optional[str]) -> list[tuple]:
|
||||||
"""List children for the given snapshot of a volume(image).
|
"""List children for the given snapshot of a volume(image).
|
||||||
|
|
||||||
Returns a list of (pool, image).
|
Returns a list of (pool, image).
|
||||||
@ -1429,7 +1431,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
with RBDVolumeProxy(self, volume.name) as image:
|
with RBDVolumeProxy(self, volume.name) as image:
|
||||||
image.rollback_to_snap(snapshot.name)
|
image.rollback_to_snap(snapshot.name)
|
||||||
|
|
||||||
def _disable_replication(self, volume: Volume) -> Dict[str, Optional[str]]:
|
def _disable_replication(self, volume: Volume) -> dict[str, Optional[str]]:
|
||||||
"""Disable replication on the given volume."""
|
"""Disable replication on the given volume."""
|
||||||
vol_name = utils.convert_str(volume.name)
|
vol_name = utils.convert_str(volume.name)
|
||||||
with RBDVolumeProxy(self, vol_name) as image:
|
with RBDVolumeProxy(self, vol_name) as image:
|
||||||
@ -1450,18 +1452,18 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
new_type: VolumeType,
|
new_type: VolumeType,
|
||||||
diff: Union[Dict[str, Dict[str, str]], Dict[str, Dict], None],
|
diff: Union[dict[str, dict[str, str]], dict[str, dict], None],
|
||||||
host: Optional[Dict[str, str]]) -> Tuple[bool, dict]:
|
host: Optional[dict[str, str]]) -> tuple[bool, dict]:
|
||||||
"""Retype from one volume type to another on the same backend."""
|
"""Retype from one volume type to another on the same backend."""
|
||||||
return True, self._setup_volume(volume, new_type)
|
return True, self._setup_volume(volume, new_type)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _dumps(obj: Dict[str, Union[bool, int]]) -> str:
|
def _dumps(obj: dict[str, Union[bool, int]]) -> str:
|
||||||
return json.dumps(obj, separators=(',', ':'), sort_keys=True)
|
return json.dumps(obj, separators=(',', ':'), sort_keys=True)
|
||||||
|
|
||||||
def _exec_on_volume(self,
|
def _exec_on_volume(self,
|
||||||
volume_name: str,
|
volume_name: str,
|
||||||
remote: Dict[str, str],
|
remote: dict[str, str],
|
||||||
operation: str,
|
operation: str,
|
||||||
*args: Any,
|
*args: Any,
|
||||||
**kwargs: Any):
|
**kwargs: Any):
|
||||||
@ -1477,9 +1479,9 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def _failover_volume(self,
|
def _failover_volume(self,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
remote: Dict[str, str],
|
remote: dict[str, str],
|
||||||
is_demoted: bool,
|
is_demoted: bool,
|
||||||
replication_status: str) -> Dict[str, Any]:
|
replication_status: str) -> dict[str, Any]:
|
||||||
"""Process failover for a volume.
|
"""Process failover for a volume.
|
||||||
|
|
||||||
There are 2 different cases that will return different update values
|
There are 2 different cases that will return different update values
|
||||||
@ -1519,8 +1521,8 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
return error_result
|
return error_result
|
||||||
|
|
||||||
def _demote_volumes(self,
|
def _demote_volumes(self,
|
||||||
volumes: List[Volume],
|
volumes: list[Volume],
|
||||||
until_failure: bool = True) -> List[bool]:
|
until_failure: bool = True) -> list[bool]:
|
||||||
"""Try to demote volumes on the current primary cluster."""
|
"""Try to demote volumes on the current primary cluster."""
|
||||||
result = []
|
result = []
|
||||||
try_demoting = True
|
try_demoting = True
|
||||||
@ -1542,7 +1544,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def _get_failover_target_config(
|
def _get_failover_target_config(
|
||||||
self,
|
self,
|
||||||
secondary_id: Optional[str] = None) -> Tuple[str, dict]:
|
secondary_id: Optional[str] = None) -> tuple[str, dict]:
|
||||||
if not secondary_id:
|
if not secondary_id:
|
||||||
# In auto mode exclude failback and active
|
# In auto mode exclude failback and active
|
||||||
candidates = set(self._target_names).difference(
|
candidates = set(self._target_names).difference(
|
||||||
@ -1557,7 +1559,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volumes: list,
|
volumes: list,
|
||||||
secondary_id: Optional[str] = None,
|
secondary_id: Optional[str] = None,
|
||||||
groups=None) -> Tuple[str, list, list]:
|
groups=None) -> tuple[str, list, list]:
|
||||||
"""Failover replicated volumes."""
|
"""Failover replicated volumes."""
|
||||||
LOG.info('RBD driver failover started.')
|
LOG.info('RBD driver failover started.')
|
||||||
if not self._is_replication_enabled:
|
if not self._is_replication_enabled:
|
||||||
@ -1595,11 +1597,11 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def failover_host(self,
|
def failover_host(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volumes: List[Volume],
|
volumes: list[Volume],
|
||||||
secondary_id: Optional[str] = None,
|
secondary_id: Optional[str] = None,
|
||||||
groups: Optional[List] = None) -> Tuple[str,
|
groups: Optional[list] = None) -> tuple[str,
|
||||||
List[Volume],
|
list[Volume],
|
||||||
List]:
|
list]:
|
||||||
"""Failover to replication target.
|
"""Failover to replication target.
|
||||||
|
|
||||||
This function combines calls to failover() and failover_completed() to
|
This function combines calls to failover() and failover_completed() to
|
||||||
@ -1631,7 +1633,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def initialize_connection(self,
|
def initialize_connection(self,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
connector: dict) -> Dict[str, Any]:
|
connector: dict) -> dict[str, Any]:
|
||||||
hosts, ports = self._get_mon_addrs()
|
hosts, ports = self._get_mon_addrs()
|
||||||
name, conf, user, secret_uuid = self._get_config_tuple()
|
name, conf, user, secret_uuid = self._get_config_tuple()
|
||||||
data = {
|
data = {
|
||||||
@ -1662,7 +1664,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_location(location: str) -> List[str]:
|
def _parse_location(location: str) -> list[str]:
|
||||||
prefix = 'rbd://'
|
prefix = 'rbd://'
|
||||||
if not location.startswith(prefix):
|
if not location.startswith(prefix):
|
||||||
reason = _('Not stored in rbd')
|
reason = _('Not stored in rbd')
|
||||||
@ -1729,7 +1731,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
volume: Volume,
|
volume: Volume,
|
||||||
image_location: Optional[list],
|
image_location: Optional[list],
|
||||||
image_meta: dict,
|
image_meta: dict,
|
||||||
image_service) -> Tuple[dict, bool]:
|
image_service) -> tuple[dict, bool]:
|
||||||
if image_location:
|
if image_location:
|
||||||
# Note: image_location[0] is glance image direct_url.
|
# Note: image_location[0] is glance image direct_url.
|
||||||
# image_location[1] contains the list of all locations (including
|
# image_location[1] contains the list of all locations (including
|
||||||
@ -1885,7 +1887,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
{'old_size': old_size, 'new_size': new_size})
|
{'old_size': old_size, 'new_size': new_size})
|
||||||
|
|
||||||
def manage_existing(self,
|
def manage_existing(self,
|
||||||
volume: Volume, existing_ref: Dict[str, str]) -> None:
|
volume: Volume, existing_ref: dict[str, str]) -> None:
|
||||||
"""Manages an existing image.
|
"""Manages an existing image.
|
||||||
|
|
||||||
Renames the image name to match the expected name for the volume.
|
Renames the image name to match the expected name for the volume.
|
||||||
@ -1906,7 +1908,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def manage_existing_get_size(self,
|
def manage_existing_get_size(self,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
existing_ref: Dict[str, str]) -> int:
|
existing_ref: dict[str, str]) -> int:
|
||||||
"""Return size of an existing image for manage_existing.
|
"""Return size of an existing image for manage_existing.
|
||||||
|
|
||||||
:param volume:
|
:param volume:
|
||||||
@ -1963,12 +1965,12 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
return json.loads(out)
|
return json.loads(out)
|
||||||
|
|
||||||
def get_manageable_volumes(self,
|
def get_manageable_volumes(self,
|
||||||
cinder_volumes: List[Dict[str, str]],
|
cinder_volumes: list[dict[str, str]],
|
||||||
marker: Optional[Any],
|
marker: Optional[Any],
|
||||||
limit: int,
|
limit: int,
|
||||||
offset: int,
|
offset: int,
|
||||||
sort_keys: List[str],
|
sort_keys: list[str],
|
||||||
sort_dirs: List[str]) -> List[Dict[str, Any]]:
|
sort_dirs: list[str]) -> list[dict[str, Any]]:
|
||||||
manageable_volumes = []
|
manageable_volumes = []
|
||||||
cinder_ids = [resource['id'] for resource in cinder_volumes]
|
cinder_ids = [resource['id'] for resource in cinder_volumes]
|
||||||
|
|
||||||
@ -2016,11 +2018,11 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def update_migrated_volume(self,
|
def update_migrated_volume(self,
|
||||||
ctxt: Dict,
|
ctxt: dict,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
new_volume: Volume,
|
new_volume: Volume,
|
||||||
original_volume_status: str) -> \
|
original_volume_status: str) -> \
|
||||||
Union[Dict[str, None], Dict[str, Optional[str]]]:
|
Union[dict[str, None], dict[str, Optional[str]]]:
|
||||||
"""Return model update from RBD for migrated volume.
|
"""Return model update from RBD for migrated volume.
|
||||||
|
|
||||||
This method should rename the back-end volume name(id) on the
|
This method should rename the back-end volume name(id) on the
|
||||||
@ -2064,7 +2066,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
def migrate_volume(self,
|
def migrate_volume(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: Volume,
|
volume: Volume,
|
||||||
host: Dict[str, Dict[str, str]]) -> Tuple[bool, None]:
|
host: dict[str, dict[str, str]]) -> tuple[bool, None]:
|
||||||
|
|
||||||
refuse_to_migrate = (False, None)
|
refuse_to_migrate = (False, None)
|
||||||
|
|
||||||
@ -2146,7 +2148,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def manage_existing_snapshot_get_size(self,
|
def manage_existing_snapshot_get_size(self,
|
||||||
snapshot: Snapshot,
|
snapshot: Snapshot,
|
||||||
existing_ref: Dict[str, Any]) -> int:
|
existing_ref: dict[str, Any]) -> int:
|
||||||
"""Return size of an existing image for manage_existing.
|
"""Return size of an existing image for manage_existing.
|
||||||
|
|
||||||
:param snapshot:
|
:param snapshot:
|
||||||
@ -2197,7 +2199,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def manage_existing_snapshot(self,
|
def manage_existing_snapshot(self,
|
||||||
snapshot: Snapshot,
|
snapshot: Snapshot,
|
||||||
existing_ref: Dict[str, Any]) -> None:
|
existing_ref: dict[str, Any]) -> None:
|
||||||
"""Manages an existing snapshot.
|
"""Manages an existing snapshot.
|
||||||
|
|
||||||
Renames the snapshot name to match the expected name for the snapshot.
|
Renames the snapshot name to match the expected name for the snapshot.
|
||||||
@ -2220,12 +2222,12 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
volume.protect_snap(snapshot.name)
|
volume.protect_snap(snapshot.name)
|
||||||
|
|
||||||
def get_manageable_snapshots(self,
|
def get_manageable_snapshots(self,
|
||||||
cinder_snapshots: List[Dict[str, str]],
|
cinder_snapshots: list[dict[str, str]],
|
||||||
marker: Optional[Any],
|
marker: Optional[Any],
|
||||||
limit: int,
|
limit: int,
|
||||||
offset: int,
|
offset: int,
|
||||||
sort_keys: List[str],
|
sort_keys: list[str],
|
||||||
sort_dirs: List[str]) -> List[Dict[str, Any]]:
|
sort_dirs: list[str]) -> list[dict[str, Any]]:
|
||||||
"""List manageable snapshots on RBD backend."""
|
"""List manageable snapshots on RBD backend."""
|
||||||
manageable_snapshots = []
|
manageable_snapshots = []
|
||||||
cinder_snapshot_ids = [resource['id'] for resource in cinder_snapshots]
|
cinder_snapshot_ids = [resource['id'] for resource in cinder_snapshots]
|
||||||
@ -2286,7 +2288,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
|
|
||||||
def get_backup_device(self,
|
def get_backup_device(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
backup: Backup) -> Tuple[Volume, bool]:
|
backup: Backup) -> tuple[Volume, bool]:
|
||||||
"""Get a backup device from an existing volume.
|
"""Get a backup device from an existing volume.
|
||||||
|
|
||||||
To support incremental backups on Ceph to Ceph we don't clone
|
To support incremental backups on Ceph to Ceph we don't clone
|
||||||
|
@ -10,7 +10,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional, Tuple, Type, Union # noqa: H301
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
|
from typing import Any, Optional, Type, Union # noqa: H301
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -82,10 +85,10 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_resource(resource: Optional[dict],
|
def _extract_resource(resource: Optional[dict],
|
||||||
allowed_vals: Tuple[Tuple[str, ...]],
|
allowed_vals: tuple[tuple[str, ...]],
|
||||||
exc: Type[exception.CinderException],
|
exc: Type[exception.CinderException],
|
||||||
resource_name: str,
|
resource_name: str,
|
||||||
props: Tuple[str] = ('status',)) -> Optional[str]:
|
props: tuple[str] = ('status',)) -> Optional[str]:
|
||||||
"""Extracts the resource id from the provided resource.
|
"""Extracts the resource id from the provided resource.
|
||||||
|
|
||||||
This method validates the input resource dict and checks that the
|
This method validates the input resource dict and checks that the
|
||||||
@ -233,7 +236,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
def _get_image_metadata(self,
|
def _get_image_metadata(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
image_id: Optional[str],
|
image_id: Optional[str],
|
||||||
size: int) -> Optional[Dict[str, Any]]:
|
size: int) -> Optional[dict[str, Any]]:
|
||||||
"""Checks image existence and validates the image metadata.
|
"""Checks image existence and validates the image metadata.
|
||||||
|
|
||||||
Returns: image metadata or None
|
Returns: image metadata or None
|
||||||
@ -257,7 +260,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
snapshot,
|
snapshot,
|
||||||
source_volume,
|
source_volume,
|
||||||
group: Optional[dict],
|
group: Optional[dict],
|
||||||
volume_type: Optional[Dict[str, Any]] = None) -> Tuple[List[str],
|
volume_type: Optional[dict[str, Any]] = None) -> tuple[list[str],
|
||||||
bool]:
|
bool]:
|
||||||
"""Extracts and returns a validated availability zone list.
|
"""Extracts and returns a validated availability zone list.
|
||||||
|
|
||||||
@ -358,7 +361,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
volume_type_id: str,
|
volume_type_id: str,
|
||||||
snapshot: Optional[objects.Snapshot],
|
snapshot: Optional[objects.Snapshot],
|
||||||
source_volume: Optional[objects.Volume],
|
source_volume: Optional[objects.Volume],
|
||||||
image_metadata: Optional[Dict[str, Any]]) -> Optional[str]:
|
image_metadata: Optional[dict[str, Any]]) -> Optional[str]:
|
||||||
if volume_types.is_encrypted(context, volume_type_id):
|
if volume_types.is_encrypted(context, volume_type_id):
|
||||||
encryption_key_id = None
|
encryption_key_id = None
|
||||||
|
|
||||||
@ -442,7 +445,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
group,
|
group,
|
||||||
group_snapshot,
|
group_snapshot,
|
||||||
backup: Optional[dict],
|
backup: Optional[dict],
|
||||||
multiattach: bool = False) -> Dict[str, Any]:
|
multiattach: bool = False) -> dict[str, Any]:
|
||||||
|
|
||||||
utils.check_exclusive_options(snapshot=snapshot,
|
utils.check_exclusive_options(snapshot=snapshot,
|
||||||
imageRef=image_id,
|
imageRef=image_id,
|
||||||
@ -502,7 +505,7 @@ class ExtractVolumeRequestTask(flow_utils.CinderTask):
|
|||||||
if multiattach:
|
if multiattach:
|
||||||
context.authorize(policy.MULTIATTACH_POLICY)
|
context.authorize(policy.MULTIATTACH_POLICY)
|
||||||
|
|
||||||
specs: Optional[Dict] = {}
|
specs: Optional[dict] = {}
|
||||||
if volume_type_id:
|
if volume_type_id:
|
||||||
qos_specs = volume_types.get_volume_type_qos_specs(volume_type_id)
|
qos_specs = volume_types.get_volume_type_qos_specs(volume_type_id)
|
||||||
if qos_specs['qos_specs']:
|
if qos_specs['qos_specs']:
|
||||||
@ -560,7 +563,7 @@ class EntryCreateTask(flow_utils.CinderTask):
|
|||||||
def execute(self,
|
def execute(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
optional_args: dict,
|
optional_args: dict,
|
||||||
**kwargs) -> Dict[str, Any]:
|
**kwargs) -> dict[str, Any]:
|
||||||
"""Creates a database entry for the given inputs and returns details.
|
"""Creates a database entry for the given inputs and returns details.
|
||||||
|
|
||||||
Accesses the database and creates a new entry for the to be created
|
Accesses the database and creates a new entry for the to be created
|
||||||
@ -809,8 +812,8 @@ class VolumeCastTask(flow_utils.CinderTask):
|
|||||||
|
|
||||||
def _cast_create_volume(self,
|
def _cast_create_volume(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
request_spec: Dict[str, Any],
|
request_spec: dict[str, Any],
|
||||||
filter_properties: Dict) -> None:
|
filter_properties: dict) -> None:
|
||||||
source_volid = request_spec['source_volid']
|
source_volid = request_spec['source_volid']
|
||||||
volume = request_spec['volume']
|
volume = request_spec['volume']
|
||||||
snapshot_id = request_spec['snapshot_id']
|
snapshot_id = request_spec['snapshot_id']
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import traceback
|
import traceback
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Dict, List, Optional, Tuple # noqa: H301
|
from typing import Any, Optional # noqa: H301
|
||||||
|
|
||||||
from castellan import key_manager
|
from castellan import key_manager
|
||||||
import os_brick.initiator.connectors
|
import os_brick.initiator.connectors
|
||||||
@ -676,7 +678,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
volume_metadata)
|
volume_metadata)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_cinder_ids(urls: List[str]) -> List[str]:
|
def _extract_cinder_ids(urls: list[str]) -> list[str]:
|
||||||
"""Process a list of location URIs from glance
|
"""Process a list of location URIs from glance
|
||||||
|
|
||||||
:param urls: list of glance location URIs
|
:param urls: list of glance location URIs
|
||||||
@ -707,7 +709,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
context: cinder_context.RequestContext,
|
context: cinder_context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_location,
|
image_location,
|
||||||
image_meta: Dict[str, Any]) -> Tuple[None, bool]:
|
image_meta: dict[str, Any]) -> tuple[None, bool]:
|
||||||
"""Create a volume efficiently from an existing image.
|
"""Create a volume efficiently from an existing image.
|
||||||
|
|
||||||
Returns a dict of volume properties eg. provider_location,
|
Returns a dict of volume properties eg. provider_location,
|
||||||
@ -768,7 +770,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
context: cinder_context.RequestContext,
|
context: cinder_context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_location,
|
image_location,
|
||||||
image_meta: Dict[str, Any],
|
image_meta: dict[str, Any],
|
||||||
image_service) -> dict:
|
image_service) -> dict:
|
||||||
# TODO(harlowja): what needs to be rolled back in the clone if this
|
# TODO(harlowja): what needs to be rolled back in the clone if this
|
||||||
# volume create fails?? Likely this should be a subflow or broken
|
# volume create fails?? Likely this should be a subflow or broken
|
||||||
@ -804,7 +806,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
internal_context: cinder_context.RequestContext,
|
internal_context: cinder_context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_id: str,
|
image_id: str,
|
||||||
image_meta: Dict[str, Any]) -> Tuple[None, bool]:
|
image_meta: dict[str, Any]) -> tuple[None, bool]:
|
||||||
"""Attempt to create the volume using the image cache.
|
"""Attempt to create the volume using the image cache.
|
||||||
|
|
||||||
Best case this will simply clone the existing volume in the cache.
|
Best case this will simply clone the existing volume in the cache.
|
||||||
@ -853,8 +855,8 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_location: str,
|
image_location: str,
|
||||||
image_id: str,
|
image_id: str,
|
||||||
image_meta: Dict[str, Any],
|
image_meta: dict[str, Any],
|
||||||
image_service) -> Tuple[Optional[dict],
|
image_service) -> tuple[Optional[dict],
|
||||||
bool]:
|
bool]:
|
||||||
assert self.image_volume_cache is not None
|
assert self.image_volume_cache is not None
|
||||||
internal_context = cinder_context.get_internal_tenant_context()
|
internal_context = cinder_context.get_internal_tenant_context()
|
||||||
@ -895,7 +897,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_location,
|
image_location,
|
||||||
image_id: str,
|
image_id: str,
|
||||||
image_meta: Dict[str, Any],
|
image_meta: dict[str, Any],
|
||||||
image_service,
|
image_service,
|
||||||
update_cache: bool = False) -> Optional[dict]:
|
update_cache: bool = False) -> Optional[dict]:
|
||||||
# NOTE(e0ne): check for free space in image_conversion_dir before
|
# NOTE(e0ne): check for free space in image_conversion_dir before
|
||||||
@ -1045,7 +1047,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
image_location,
|
image_location,
|
||||||
image_id: str,
|
image_id: str,
|
||||||
image_meta: Dict[str, Any],
|
image_meta: dict[str, Any],
|
||||||
image_service,
|
image_service,
|
||||||
**kwargs: Any) -> Optional[dict]:
|
**kwargs: Any) -> Optional[dict]:
|
||||||
LOG.debug("Cloning %(volume_id)s from image %(image_id)s "
|
LOG.debug("Cloning %(volume_id)s from image %(image_id)s "
|
||||||
@ -1120,7 +1122,7 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
|
|||||||
context: cinder_context.RequestContext,
|
context: cinder_context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
backup_id: str,
|
backup_id: str,
|
||||||
**kwargs) -> Tuple[Dict, bool]:
|
**kwargs) -> tuple[dict, bool]:
|
||||||
LOG.info("Creating volume %(volume_id)s from backup %(backup_id)s.",
|
LOG.info("Creating volume %(volume_id)s from backup %(backup_id)s.",
|
||||||
{'volume_id': volume.id,
|
{'volume_id': volume.id,
|
||||||
'backup_id': backup_id})
|
'backup_id': backup_id})
|
||||||
|
@ -35,10 +35,12 @@ intact.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting Python 3.9+
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import time
|
import time
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union # noqa: H301
|
from typing import Any, Optional, Union # noqa: H301
|
||||||
|
|
||||||
from castellan import key_manager
|
from castellan import key_manager
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -539,7 +541,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
num_vols: int = 0
|
num_vols: int = 0
|
||||||
num_snaps: int = 0
|
num_snaps: int = 0
|
||||||
max_objs_num: int = 0
|
max_objs_num: int = 0
|
||||||
req_range: Union[List[int], range] = [0]
|
req_range: Union[list[int], range] = [0]
|
||||||
req_limit = CONF.init_host_max_objects_retrieval or 0
|
req_limit = CONF.init_host_max_objects_retrieval or 0
|
||||||
use_batch_objects_retrieval: bool = req_limit > 0
|
use_batch_objects_retrieval: bool = req_limit > 0
|
||||||
|
|
||||||
@ -1601,7 +1603,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
reservations = QUOTAS.reserve(ctx, **reserve_opts)
|
reservations = QUOTAS.reserve(ctx, **reserve_opts)
|
||||||
# NOTE(yikun): Skip 'snapshot_id', 'source_volid' keys to avoid
|
# NOTE(yikun): Skip 'snapshot_id', 'source_volid' keys to avoid
|
||||||
# creating tmp img vol from wrong snapshot or wrong source vol.
|
# creating tmp img vol from wrong snapshot or wrong source vol.
|
||||||
skip: Set[str] = {'snapshot_id', 'source_volid'}
|
skip: set[str] = {'snapshot_id', 'source_volid'}
|
||||||
skip.update(self._VOLUME_CLONE_SKIP_PROPERTIES)
|
skip.update(self._VOLUME_CLONE_SKIP_PROPERTIES)
|
||||||
try:
|
try:
|
||||||
new_vol_values = {k: volume[k] for k in set(volume.keys()) - skip}
|
new_vol_values = {k: volume[k] for k in set(volume.keys()) - skip}
|
||||||
@ -3199,7 +3201,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
|
|
||||||
return vol_ref
|
return vol_ref
|
||||||
|
|
||||||
def _get_cluster_or_host_filters(self) -> Dict[str, Any]:
|
def _get_cluster_or_host_filters(self) -> dict[str, Any]:
|
||||||
if self.cluster:
|
if self.cluster:
|
||||||
filters = {'cluster_name': self.cluster}
|
filters = {'cluster_name': self.cluster}
|
||||||
else:
|
else:
|
||||||
@ -3500,12 +3502,12 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
self,
|
self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
group: objects.Group,
|
group: objects.Group,
|
||||||
volumes: List[objects.Volume],
|
volumes: list[objects.Volume],
|
||||||
group_snapshot: Optional[objects.GroupSnapshot] = None,
|
group_snapshot: Optional[objects.GroupSnapshot] = None,
|
||||||
snapshots: Optional[List[objects.Snapshot]] = None,
|
snapshots: Optional[list[objects.Snapshot]] = None,
|
||||||
source_group: Optional[objects.Group] = None,
|
source_group: Optional[objects.Group] = None,
|
||||||
source_vols: Optional[List[objects.Volume]] = None) \
|
source_vols: Optional[list[objects.Volume]] = None) \
|
||||||
-> Tuple[Dict[str, str], List[Dict[str, str]]]:
|
-> tuple[dict[str, str], list[dict[str, str]]]:
|
||||||
"""Creates a group from source.
|
"""Creates a group from source.
|
||||||
|
|
||||||
:param context: the context of the caller.
|
:param context: the context of the caller.
|
||||||
@ -3518,7 +3520,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
:returns: model_update, volumes_model_update
|
:returns: model_update, volumes_model_update
|
||||||
"""
|
"""
|
||||||
model_update = {'status': 'available'}
|
model_update = {'status': 'available'}
|
||||||
volumes_model_update: List[dict] = []
|
volumes_model_update: list[dict] = []
|
||||||
for vol in volumes:
|
for vol in volumes:
|
||||||
if snapshots:
|
if snapshots:
|
||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
@ -3819,7 +3821,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
def _convert_group_to_cg(
|
def _convert_group_to_cg(
|
||||||
self,
|
self,
|
||||||
group: objects.Group,
|
group: objects.Group,
|
||||||
volumes: objects.VolumeList) -> Tuple[objects.Group,
|
volumes: objects.VolumeList) -> tuple[objects.Group,
|
||||||
objects.VolumeList]:
|
objects.VolumeList]:
|
||||||
if not group:
|
if not group:
|
||||||
return None, None
|
return None, None
|
||||||
@ -3832,7 +3834,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
return cg, volumes
|
return cg, volumes
|
||||||
|
|
||||||
def _remove_consistencygroup_id_from_volumes(
|
def _remove_consistencygroup_id_from_volumes(
|
||||||
self, volumes: Optional[List[objects.Volume]]) -> None:
|
self, volumes: Optional[list[objects.Volume]]) -> None:
|
||||||
if not volumes:
|
if not volumes:
|
||||||
return
|
return
|
||||||
for vol in volumes:
|
for vol in volumes:
|
||||||
@ -3843,7 +3845,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
self,
|
self,
|
||||||
group_snapshot: objects.GroupSnapshot,
|
group_snapshot: objects.GroupSnapshot,
|
||||||
snapshots: objects.SnapshotList,
|
snapshots: objects.SnapshotList,
|
||||||
ctxt) -> Tuple[objects.CGSnapshot,
|
ctxt) -> tuple[objects.CGSnapshot,
|
||||||
objects.SnapshotList]:
|
objects.SnapshotList]:
|
||||||
if not group_snapshot:
|
if not group_snapshot:
|
||||||
return None, None
|
return None, None
|
||||||
@ -3881,7 +3883,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
def _delete_group_generic(self,
|
def _delete_group_generic(self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
group: objects.Group,
|
group: objects.Group,
|
||||||
volumes) -> Tuple:
|
volumes) -> tuple:
|
||||||
"""Deletes a group and volumes in the group."""
|
"""Deletes a group and volumes in the group."""
|
||||||
model_update = {'status': group.status}
|
model_update = {'status': group.status}
|
||||||
volume_model_updates = []
|
volume_model_updates = []
|
||||||
@ -3903,7 +3905,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
def _update_group_generic(
|
def _update_group_generic(
|
||||||
self, context: context.RequestContext, group,
|
self, context: context.RequestContext, group,
|
||||||
add_volumes=None,
|
add_volumes=None,
|
||||||
remove_volumes=None) -> Tuple[None, None, None]:
|
remove_volumes=None) -> tuple[None, None, None]:
|
||||||
"""Updates a group."""
|
"""Updates a group."""
|
||||||
# NOTE(xyang): The volume manager adds/removes the volume to/from the
|
# NOTE(xyang): The volume manager adds/removes the volume to/from the
|
||||||
# group in the database. This default implementation does not do
|
# group in the database. This default implementation does not do
|
||||||
@ -3916,7 +3918,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
group,
|
group,
|
||||||
volumes: Optional[str],
|
volumes: Optional[str],
|
||||||
add: bool = True) -> list:
|
add: bool = True) -> list:
|
||||||
valid_status: Tuple[str, ...]
|
valid_status: tuple[str, ...]
|
||||||
if add:
|
if add:
|
||||||
valid_status = VALID_ADD_VOL_TO_GROUP_STATUS
|
valid_status = VALID_ADD_VOL_TO_GROUP_STATUS
|
||||||
else:
|
else:
|
||||||
@ -4182,7 +4184,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
self,
|
self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
group_snapshot: objects.GroupSnapshot,
|
group_snapshot: objects.GroupSnapshot,
|
||||||
snapshots: list) -> Tuple[dict, List[dict]]:
|
snapshots: list) -> tuple[dict, list[dict]]:
|
||||||
"""Creates a group_snapshot."""
|
"""Creates a group_snapshot."""
|
||||||
model_update = {'status': 'available'}
|
model_update = {'status': 'available'}
|
||||||
snapshot_model_updates = []
|
snapshot_model_updates = []
|
||||||
@ -4208,7 +4210,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
self,
|
self,
|
||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
group_snapshot: objects.GroupSnapshot,
|
group_snapshot: objects.GroupSnapshot,
|
||||||
snapshots: list) -> Tuple[dict, List[dict]]:
|
snapshots: list) -> tuple[dict, list[dict]]:
|
||||||
"""Deletes a group_snapshot."""
|
"""Deletes a group_snapshot."""
|
||||||
model_update = {'status': group_snapshot.status}
|
model_update = {'status': group_snapshot.status}
|
||||||
snapshot_model_updates = []
|
snapshot_model_updates = []
|
||||||
@ -4772,7 +4774,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
ctxt: context.RequestContext,
|
ctxt: context.RequestContext,
|
||||||
volume: objects.Volume,
|
volume: objects.Volume,
|
||||||
attachment: objects.VolumeAttachment,
|
attachment: objects.VolumeAttachment,
|
||||||
connector: dict) -> Dict[str, Any]:
|
connector: dict) -> dict[str, Any]:
|
||||||
try:
|
try:
|
||||||
self.driver.validate_connector(connector)
|
self.driver.validate_connector(connector)
|
||||||
except exception.InvalidConnectorException as err:
|
except exception.InvalidConnectorException as err:
|
||||||
@ -4830,7 +4832,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
vref: objects.Volume,
|
vref: objects.Volume,
|
||||||
connector: dict,
|
connector: dict,
|
||||||
attachment_id: str) -> Dict[str, Any]:
|
attachment_id: str) -> dict[str, Any]:
|
||||||
"""Update/Finalize an attachment.
|
"""Update/Finalize an attachment.
|
||||||
|
|
||||||
This call updates a valid attachment record to associate with a volume
|
This call updates a valid attachment record to associate with a volume
|
||||||
@ -5236,7 +5238,7 @@ class VolumeManager(manager.CleanableManager,
|
|||||||
|
|
||||||
def list_replication_targets(self,
|
def list_replication_targets(self,
|
||||||
ctxt: context.RequestContext,
|
ctxt: context.RequestContext,
|
||||||
group: objects.Group) -> Dict[str, list]:
|
group: objects.Group) -> dict[str, list]:
|
||||||
"""Provide a means to obtain replication targets for a group.
|
"""Provide a means to obtain replication targets for a group.
|
||||||
|
|
||||||
This method is used to find the replication_device config
|
This method is used to find the replication_device config
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from typing import Optional, Tuple, Union # noqa: H301
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional, Union # noqa: H301
|
||||||
|
|
||||||
from cinder.common import constants
|
from cinder.common import constants
|
||||||
from cinder import context
|
from cinder import context
|
||||||
@ -147,7 +149,7 @@ class VolumeAPI(rpc.RPCAPI):
|
|||||||
|
|
||||||
def _get_cctxt(self,
|
def _get_cctxt(self,
|
||||||
host: Optional[str] = None,
|
host: Optional[str] = None,
|
||||||
version: Optional[Union[str, Tuple[str, ...]]] = None,
|
version: Optional[Union[str, tuple[str, ...]]] = None,
|
||||||
**kwargs) -> rpc.RPCAPI:
|
**kwargs) -> rpc.RPCAPI:
|
||||||
if host:
|
if host:
|
||||||
server = volume_utils.extract_host(host)
|
server = volume_utils.extract_host(host)
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
"""Built-in volume type properties."""
|
"""Built-in volume type properties."""
|
||||||
|
|
||||||
import typing as ty
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
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
|
||||||
@ -330,7 +332,7 @@ def get_volume_type_qos_specs(volume_type_id):
|
|||||||
|
|
||||||
def volume_types_diff(context: context.RequestContext,
|
def volume_types_diff(context: context.RequestContext,
|
||||||
vol_type_id1,
|
vol_type_id1,
|
||||||
vol_type_id2) -> ty.Tuple[dict, bool]:
|
vol_type_id2) -> tuple[dict, bool]:
|
||||||
"""Returns a 'diff' of two volume types and whether they are equal.
|
"""Returns a 'diff' of two volume types and whether they are equal.
|
||||||
|
|
||||||
Returns a tuple of (diff, equal), where 'equal' is a boolean indicating
|
Returns a tuple of (diff, equal), where 'equal' is a boolean indicating
|
||||||
@ -370,8 +372,8 @@ def volume_types_diff(context: context.RequestContext,
|
|||||||
encryption.pop(param, None)
|
encryption.pop(param, None)
|
||||||
return encryption
|
return encryption
|
||||||
|
|
||||||
def _dict_diff(dict1: ty.Optional[dict],
|
def _dict_diff(dict1: Optional[dict],
|
||||||
dict2: ty.Optional[dict]) -> ty.Tuple[dict, bool]:
|
dict2: Optional[dict]) -> tuple[dict, bool]:
|
||||||
res = {}
|
res = {}
|
||||||
equal = True
|
equal = True
|
||||||
if dict1 is None:
|
if dict1 is None:
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
"""Volume-related Utilities and helpers."""
|
"""Volume-related Utilities and helpers."""
|
||||||
|
|
||||||
|
from __future__ import annotations # Remove when only supporting python 3.9+
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
import ast
|
import ast
|
||||||
import functools
|
import functools
|
||||||
@ -31,8 +33,8 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
import types
|
import types
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, BinaryIO, Callable, Dict, IO # noqa: H301
|
from typing import Any, BinaryIO, Callable, IO # noqa: H301
|
||||||
from typing import List, Optional, Tuple, Union # noqa: H301
|
from typing import Optional, Union # noqa: H301
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from castellan.common.credentials import keystone_password
|
from castellan.common.credentials import keystone_password
|
||||||
@ -242,8 +244,8 @@ def notify_about_snapshot_usage(context: context.RequestContext,
|
|||||||
usage_info)
|
usage_info)
|
||||||
|
|
||||||
|
|
||||||
def _usage_from_capacity(capacity: Dict[str, Any],
|
def _usage_from_capacity(capacity: dict[str, Any],
|
||||||
**extra_usage_info) -> Dict[str, Any]:
|
**extra_usage_info) -> dict[str, Any]:
|
||||||
|
|
||||||
capacity_info = {
|
capacity_info = {
|
||||||
'name_to_id': capacity['name_to_id'],
|
'name_to_id': capacity['name_to_id'],
|
||||||
@ -686,7 +688,7 @@ def get_all_volume_groups(vg_name=None) -> list:
|
|||||||
|
|
||||||
def extract_availability_zones_from_volume_type(
|
def extract_availability_zones_from_volume_type(
|
||||||
volume_type: Union['objects.VolumeType', dict]) \
|
volume_type: Union['objects.VolumeType', dict]) \
|
||||||
-> Optional[List[str]]:
|
-> Optional[list[str]]:
|
||||||
if not volume_type:
|
if not volume_type:
|
||||||
return None
|
return None
|
||||||
extra_specs = volume_type.get('extra_specs', {})
|
extra_specs = volume_type.get('extra_specs', {})
|
||||||
@ -705,7 +707,7 @@ DEFAULT_PASSWORD_SYMBOLS = ('23456789', # Removed: 0,1
|
|||||||
|
|
||||||
def generate_password(
|
def generate_password(
|
||||||
length: int = 16,
|
length: int = 16,
|
||||||
symbolgroups: Tuple[str, ...] = DEFAULT_PASSWORD_SYMBOLS) -> str:
|
symbolgroups: tuple[str, ...] = DEFAULT_PASSWORD_SYMBOLS) -> str:
|
||||||
"""Generate a random password from the supplied symbol groups.
|
"""Generate a random password from the supplied symbol groups.
|
||||||
|
|
||||||
At least one symbol from each group will be included. Unpredictable
|
At least one symbol from each group will be included. Unpredictable
|
||||||
@ -744,7 +746,7 @@ def generate_password(
|
|||||||
|
|
||||||
def generate_username(
|
def generate_username(
|
||||||
length: int = 20,
|
length: int = 20,
|
||||||
symbolgroups: Tuple[str, ...] = DEFAULT_PASSWORD_SYMBOLS) -> str:
|
symbolgroups: tuple[str, ...] = DEFAULT_PASSWORD_SYMBOLS) -> str:
|
||||||
# Use the same implementation as the password generation.
|
# Use the same implementation as the password generation.
|
||||||
return generate_password(length, symbolgroups)
|
return generate_password(length, symbolgroups)
|
||||||
|
|
||||||
@ -864,12 +866,12 @@ def extract_id_from_snapshot_name(snap_name: str) -> Optional[str]:
|
|||||||
return match.group('uuid') if match else None
|
return match.group('uuid') if match else None
|
||||||
|
|
||||||
|
|
||||||
def paginate_entries_list(entries: List[Dict],
|
def paginate_entries_list(entries: list[dict],
|
||||||
marker: Optional[Union[dict, str]],
|
marker: Optional[Union[dict, str]],
|
||||||
limit: int,
|
limit: int,
|
||||||
offset: Optional[int],
|
offset: Optional[int],
|
||||||
sort_keys: List[str],
|
sort_keys: list[str],
|
||||||
sort_dirs: List[str]) -> list:
|
sort_dirs: list[str]) -> list:
|
||||||
"""Paginate a list of entries.
|
"""Paginate a list of entries.
|
||||||
|
|
||||||
:param entries: list of dictionaries
|
:param entries: list of dictionaries
|
||||||
@ -1096,7 +1098,7 @@ def get_max_over_subscription_ratio(
|
|||||||
return mosr
|
return mosr
|
||||||
|
|
||||||
|
|
||||||
def check_image_metadata(image_meta: Dict[str, Union[str, int]],
|
def check_image_metadata(image_meta: dict[str, Union[str, int]],
|
||||||
vol_size: int) -> None:
|
vol_size: int) -> None:
|
||||||
"""Validates the image metadata."""
|
"""Validates the image metadata."""
|
||||||
# Check whether image is active
|
# Check whether image is active
|
||||||
@ -1136,7 +1138,7 @@ def enable_bootable_flag(volume: 'objects.Volume') -> None:
|
|||||||
|
|
||||||
|
|
||||||
def get_volume_image_metadata(image_id: str,
|
def get_volume_image_metadata(image_id: str,
|
||||||
image_meta: Dict[str, Any]) -> dict:
|
image_meta: dict[str, Any]) -> dict:
|
||||||
|
|
||||||
# Save some base attributes into the volume metadata
|
# Save some base attributes into the volume metadata
|
||||||
base_metadata = {
|
base_metadata = {
|
||||||
@ -1172,7 +1174,7 @@ def copy_image_to_volume(driver,
|
|||||||
context: context.RequestContext,
|
context: context.RequestContext,
|
||||||
volume: 'objects.Volume',
|
volume: 'objects.Volume',
|
||||||
image_meta: dict,
|
image_meta: dict,
|
||||||
image_location: Union[str, Tuple[Optional[str], Any]],
|
image_location: Union[str, tuple[Optional[str], Any]],
|
||||||
image_service) -> None:
|
image_service) -> None:
|
||||||
"""Downloads Glance image to the specified volume."""
|
"""Downloads Glance image to the specified volume."""
|
||||||
image_id = image_meta['id']
|
image_id = image_meta['id']
|
||||||
|
Loading…
Reference in New Issue
Block a user