Merge "mypy: image cache"
This commit is contained in:
commit
799182036f
@ -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'],
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user