Merge "mypy: image cache"

This commit is contained in:
Zuul 2021-08-18 22:29:41 +00:00 committed by Gerrit Code Review
commit 799182036f
4 changed files with 67 additions and 20 deletions

View File

@ -12,11 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from typing import Optional
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import timeutils
from pytz import timezone
from cinder import context
from cinder import objects
from cinder import rpc
from cinder import utils
@ -27,18 +30,25 @@ LOG = logging.getLogger(__name__)
class ImageVolumeCache(object):
def __init__(self, db, volume_api, max_cache_size_gb=0,
max_cache_size_count=0):
def __init__(self,
db,
volume_api,
max_cache_size_gb: int = 0,
max_cache_size_count: int = 0):
self.db = db
self.volume_api = volume_api
self.max_cache_size_gb = int(max_cache_size_gb)
self.max_cache_size_count = int(max_cache_size_count)
self.notifier = rpc.get_notifier('volume', CONF.host)
def get_by_image_volume(self, context, volume_id):
def get_by_image_volume(self,
context: context.RequestContext,
volume_id: str):
return self.db.image_volume_cache_get_by_volume_id(context, volume_id)
def evict(self, context, cache_entry):
def evict(self,
context: context.RequestContext,
cache_entry: dict) -> None:
LOG.debug('Evicting image cache entry: %(entry)s.',
{'entry': self._entry_to_str(cache_entry)})
self.db.image_volume_cache_delete(context, cache_entry['volume_id'])
@ -46,12 +56,16 @@ class ImageVolumeCache(object):
cache_entry['host'])
@staticmethod
def _get_query_filters(volume_ref):
def _get_query_filters(volume_ref: objects.Volume) -> dict:
if volume_ref.is_clustered:
return {'cluster_name': volume_ref.cluster_name}
return {'host': volume_ref.host}
def get_entry(self, context, volume_ref, image_id, image_meta):
def get_entry(self,
context: context.RequestContext,
volume_ref: objects.Volume,
image_id: str,
image_meta: dict) -> Optional[dict]:
cache_entry = self.db.image_volume_cache_get_and_update_last_used(
context,
image_id,
@ -77,7 +91,11 @@ class ImageVolumeCache(object):
volume_ref['host'])
return cache_entry
def create_cache_entry(self, context, volume_ref, image_id, image_meta):
def create_cache_entry(self,
context: context.RequestContext,
volume_ref: objects.Volume,
image_id: str,
image_meta: dict) -> dict:
"""Create a new cache entry for an image.
This assumes that the volume described by volume_ref has already been
@ -112,7 +130,9 @@ class ImageVolumeCache(object):
{'entry': self._entry_to_str(cache_entry)})
return cache_entry
def ensure_space(self, context, volume):
def ensure_space(self,
context: context.RequestContext,
volume: objects.Volume) -> bool:
"""Makes room for a volume cache entry.
Returns True if successful, false otherwise.
@ -184,19 +204,32 @@ class ImageVolumeCache(object):
return True
@utils.if_notifications_enabled
def _notify_cache_hit(self, context, image_id, host):
def _notify_cache_hit(self,
context: context.RequestContext,
image_id: str,
host: str) -> None:
self._notify_cache_action(context, image_id, host, 'hit')
@utils.if_notifications_enabled
def _notify_cache_miss(self, context, image_id, host):
def _notify_cache_miss(self,
context: context.RequestContext,
image_id: str,
host: str) -> None:
self._notify_cache_action(context, image_id, host, 'miss')
@utils.if_notifications_enabled
def _notify_cache_eviction(self, context, image_id, host):
def _notify_cache_eviction(self,
context: context.RequestContext,
image_id: str,
host: str) -> None:
self._notify_cache_action(context, image_id, host, 'evict')
@utils.if_notifications_enabled
def _notify_cache_action(self, context, image_id, host, action):
def _notify_cache_action(self,
context: context.RequestContext,
image_id: str,
host: str,
action: str) -> None:
data = {
'image_id': image_id,
'host': host,
@ -205,14 +238,18 @@ class ImageVolumeCache(object):
' data=%(data)s.', {'action': action, 'data': data})
self.notifier.info(context, 'image_volume_cache.%s' % action, data)
def _delete_image_volume(self, context, cache_entry):
def _delete_image_volume(self,
context: context.RequestContext,
cache_entry: dict) -> None:
"""Delete a volume and remove cache entry."""
volume = objects.Volume.get_by_id(context, cache_entry['volume_id'])
# Delete will evict the cache entry.
self.volume_api.delete(context, volume)
def _should_update_entry(self, cache_entry, image_meta):
def _should_update_entry(self,
cache_entry: dict,
image_meta: dict) -> bool:
"""Ensure that the cache entry image data is still valid."""
image_updated_utc = (image_meta['updated_at']
.astimezone(timezone('UTC')))
@ -226,7 +263,7 @@ class ImageVolumeCache(object):
return image_updated_utc != cache_updated_utc
def _entry_to_str(self, cache_entry):
def _entry_to_str(self, cache_entry: dict) -> str:
return str({
'id': cache_entry['id'],
'image_id': cache_entry['image_id'],

View File

@ -23,8 +23,10 @@ import shutil
import sys
import textwrap
import time
import typing as ty
import typing
from typing import Any, Dict, Tuple # noqa: H301
import urllib
import urllib.parse
import glanceclient.exc
from keystoneauth1.loading import session as ks_session
@ -304,7 +306,9 @@ class GlanceImageService(object):
except Exception:
_reraise_translated_exception()
def show(self, context, image_id):
def show(self,
context: context.RequestContext,
image_id: str) -> Dict[str, Any]:
"""Returns a dict with image data for the given opaque image id."""
try:
image = self._client.call(context, 'get', image_id)
@ -352,6 +356,7 @@ class GlanceImageService(object):
except Exception:
_reraise_translated_image_exception(image_id)
@typing.no_type_check
def download(self, context, image_id, data=None):
"""Calls out to Glance for data and writes data."""
if data and 'file' in CONF.allowed_direct_url_schemes:
@ -452,7 +457,7 @@ class GlanceImageService(object):
raise exception.ImageNotFound(image_id=image_id)
return True
def _translate_from_glance(self, context, image):
def _translate_from_glance(self, context, image) -> dict:
"""Get image metadata from glance image.
Extract metadata from image and convert it's properties
@ -595,7 +600,7 @@ def _extract_attributes(image):
'visibility',
'cinder_encryption_key_id']
output = {}
output: Dict[str, Any] = {}
for attr in IMAGE_ATTRIBUTES:
if attr == 'deleted_at' and not output['deleted']:
@ -656,7 +661,7 @@ def _translate_plain_exception(exc_value):
def get_remote_image_service(context: context.RequestContext,
image_href) -> ty.Tuple[GlanceImageService, str]:
image_href) -> Tuple[GlanceImageService, str]:
"""Create an image_service and parse the id from the given image_href.
The image_href param can be an href of the form

View File

@ -38,6 +38,7 @@ intact.
import functools
import time
import typing as ty
from typing import Optional
from castellan import key_manager
from oslo_config import cfg
@ -261,6 +262,7 @@ class VolumeManager(manager.CleanableManager,
self.service_uuid = None
self.cluster: str
self.image_volume_cache: Optional[image_cache.ImageVolumeCache]
if not volume_driver:
# Get from configuration, which will get the default
@ -1548,6 +1550,7 @@ class VolumeManager(manager.CleanableManager,
This assumes that the image has already been downloaded and stored
in the volume described by the volume_ref.
"""
assert self.image_volume_cache is not None
cache_entry = self.image_volume_cache.get_entry(ctx,
volume_ref,
image_id,

View File

@ -1,5 +1,7 @@
cinder/context.py
cinder/i18n.py
cinder/image/cache.py
cinder/image/glance.py
cinder/image/image_utils.py
cinder/exception.py
cinder/manager.py