Enable a configurable whitelist of namespaces for V22

If a namespace is present in the whitelist, all calls are sent to the OCI model instead of the Pre OCI model

Note that this does increase overhead for registry calls (since we need to lookup the namespace for every single call), but it should only be temporary until we've migrated all users over to the OCI data model
This commit is contained in:
Joseph Schorr 2018-12-03 14:19:53 -05:00
parent 50dc57acdf
commit d59bea3569
7 changed files with 115 additions and 12 deletions

View file

@ -0,0 +1,82 @@
import inspect
import logging
from data.database import DerivedStorageForImage, TagManifest, Manifest, Image
from data.registry_model.registry_oci_model import oci_model
from data.registry_model.registry_pre_oci_model import pre_oci_model
from data.registry_model.datatypes import LegacyImage, Manifest as ManifestDataType
logger = logging.getLogger(__name__)
class SplitModel(object):
def __init__(self, v22_namespace_whitelist):
self.v22_namespace_whitelist = set(v22_namespace_whitelist)
def supports_schema2(self, namespace_name):
""" Returns whether the implementation of the data interface supports schema 2 format
manifests. """
return namespace_name in self.v22_namespace_whitelist
def _namespace_from_kwargs(self, args_dict):
if 'namespace_name' in args_dict:
return args_dict['namespace_name']
if 'repository_ref' in args_dict:
return args_dict['repository_ref'].namespace_name
if 'tag' in args_dict:
return args_dict['tag'].repository.namespace_name
if 'manifest' in args_dict:
manifest = args_dict['manifest']
if manifest._is_tag_manifest:
return TagManifest.get(id=manifest._db_id).tag.repository.namespace_user.username
else:
return Manifest.get(id=manifest._db_id).repository.namespace_user.username
if 'manifest_or_legacy_image' in args_dict:
manifest_or_legacy_image = args_dict['manifest_or_legacy_image']
if isinstance(manifest_or_legacy_image, LegacyImage):
return Image.get(id=manifest_or_legacy_image._db_id).repository.namespace_user.username
else:
manifest = manifest_or_legacy_image
if manifest._is_tag_manifest:
return TagManifest.get(id=manifest._db_id).tag.repository.namespace_user.username
else:
return Manifest.get(id=manifest._db_id).repository.namespace_user.username
if 'derived_image' in args_dict:
return (DerivedStorageForImage
.get(id=args_dict['derived_image']._db_id)
.source_image
.repository
.namespace_user
.username)
if 'blob' in args_dict:
return '' # Blob functions are shared, so no need to do anything.
if 'blob_upload' in args_dict:
return '' # Blob functions are shared, so no need to do anything.
raise Exception('Unknown namespace for dict `%s`' % args_dict)
def __getattr__(self, attr):
def method(*args, **kwargs):
argnames = inspect.getargspec(getattr(oci_model, attr))[0]
if not argnames and isinstance(args[0], ManifestDataType):
args_dict = dict(manifest=args[0])
else:
args_dict = {argnames[index + 1]: value for index, value in enumerate(args)}
namespace_name = self._namespace_from_kwargs(args_dict)
if namespace_name in self.v22_namespace_whitelist:
logger.debug('Calling method `%s` under OCI data model for namespace `%s`',
attr, namespace_name)
return getattr(oci_model, attr)(*args, **kwargs)
else:
return getattr(pre_oci_model, attr)(*args, **kwargs)
return method