Merge pull request #3374 from quay/joseph.schorr/QUAY-1309/oci-rollout
Add ability for proportional rollout of the OCI data model
This commit is contained in:
commit
46478bc603
4 changed files with 22 additions and 9 deletions
3
app.py
3
app.py
|
@ -93,7 +93,8 @@ app.config.update(environ_config)
|
||||||
|
|
||||||
# Split the registry model based on config.
|
# Split the registry model based on config.
|
||||||
# TODO(jschorr): Remove once we are fully on the OCI data model.
|
# TODO(jschorr): Remove once we are fully on the OCI data model.
|
||||||
registry_model.setup_split(app.config.get('OCI_NAMESPACE_WHITELIST') or set(),
|
registry_model.setup_split(app.config.get('OCI_NAMESPACE_PROPORTION') or 0,
|
||||||
|
app.config.get('OCI_NAMESPACE_WHITELIST') or set(),
|
||||||
app.config.get('V22_NAMESPACE_WHITELIST') or set())
|
app.config.get('V22_NAMESPACE_WHITELIST') or set())
|
||||||
|
|
||||||
# Allow user to define a custom storage preference for the local instance.
|
# Allow user to define a custom storage preference for the local instance.
|
||||||
|
|
|
@ -12,15 +12,15 @@ class RegistryModelProxy(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._model = oci_model if os.getenv('OCI_DATA_MODEL') == 'true' else pre_oci_model
|
self._model = oci_model if os.getenv('OCI_DATA_MODEL') == 'true' else pre_oci_model
|
||||||
|
|
||||||
def setup_split(self, oci_whitelist, v22_whitelist):
|
def setup_split(self, oci_model_proportion, oci_whitelist, v22_whitelist):
|
||||||
if os.getenv('OCI_DATA_MODEL') == 'true':
|
if os.getenv('OCI_DATA_MODEL') == 'true':
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info('===============================')
|
logger.info('===============================')
|
||||||
logger.info('Enabling split registry model with OCI whitelist `%s` and V22 whitelist `%s`',
|
logger.info('Split registry model: OCI %s proportion and whitelist `%s` and V22 whitelist `%s`',
|
||||||
oci_whitelist, v22_whitelist)
|
oci_model_proportion, oci_whitelist, v22_whitelist)
|
||||||
logger.info('===============================')
|
logger.info('===============================')
|
||||||
self._model = SplitModel(oci_whitelist, v22_whitelist)
|
self._model = SplitModel(oci_model_proportion, oci_whitelist, v22_whitelist)
|
||||||
|
|
||||||
def set_for_testing(self, use_oci_model):
|
def set_for_testing(self, use_oci_model):
|
||||||
self._model = oci_model if use_oci_model else pre_oci_model
|
self._model = oci_model if use_oci_model else pre_oci_model
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from data.database import DerivedStorageForImage, TagManifest, Manifest, Image
|
from data.database import DerivedStorageForImage, TagManifest, Manifest, Image
|
||||||
from data.registry_model.registry_oci_model import oci_model
|
from data.registry_model.registry_oci_model import oci_model
|
||||||
|
@ -11,12 +12,14 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SplitModel(object):
|
class SplitModel(object):
|
||||||
def __init__(self, oci_namespace_whitelist, v22_namespace_whitelist):
|
def __init__(self, oci_model_proportion, oci_namespace_whitelist, v22_namespace_whitelist):
|
||||||
self.v22_namespace_whitelist = set(v22_namespace_whitelist)
|
self.v22_namespace_whitelist = set(v22_namespace_whitelist)
|
||||||
|
|
||||||
self.oci_namespace_whitelist = set(oci_namespace_whitelist)
|
self.oci_namespace_whitelist = set(oci_namespace_whitelist)
|
||||||
self.oci_namespace_whitelist.update(v22_namespace_whitelist)
|
self.oci_namespace_whitelist.update(v22_namespace_whitelist)
|
||||||
|
|
||||||
|
self.oci_model_proportion = oci_model_proportion
|
||||||
|
|
||||||
def supports_schema2(self, namespace_name):
|
def supports_schema2(self, namespace_name):
|
||||||
""" Returns whether the implementation of the data interface supports schema 2 format
|
""" Returns whether the implementation of the data interface supports schema 2 format
|
||||||
manifests. """
|
manifests. """
|
||||||
|
@ -75,7 +78,16 @@ class SplitModel(object):
|
||||||
args_dict = {argnames[index + 1]: value for index, value in enumerate(args)}
|
args_dict = {argnames[index + 1]: value for index, value in enumerate(args)}
|
||||||
|
|
||||||
namespace_name = self._namespace_from_kwargs(args_dict)
|
namespace_name = self._namespace_from_kwargs(args_dict)
|
||||||
if namespace_name in self.oci_namespace_whitelist:
|
use_oci = namespace_name in self.oci_namespace_whitelist
|
||||||
|
if not use_oci and self.oci_model_proportion:
|
||||||
|
# Hash the namespace name and see if it falls into the proportion bucket.
|
||||||
|
bucket = (int(hashlib.md5(namespace_name).hexdigest(), 16) % 100)
|
||||||
|
if bucket <= int(self.oci_model_proportion * 100):
|
||||||
|
logger.debug('Enabling OCI for namespace `%s` in proportional bucket',
|
||||||
|
namespace_name)
|
||||||
|
use_oci = True
|
||||||
|
|
||||||
|
if use_oci:
|
||||||
logger.debug('Calling method `%s` under OCI data model for namespace `%s`',
|
logger.debug('Calling method `%s` under OCI data model for namespace `%s`',
|
||||||
attr, namespace_name)
|
attr, namespace_name)
|
||||||
return getattr(oci_model, attr)(*args, **kwargs)
|
return getattr(oci_model, attr)(*args, **kwargs)
|
||||||
|
|
|
@ -36,7 +36,7 @@ from test.fixtures import *
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(params=[PreOCIModel(), OCIModel(),
|
@pytest.fixture(params=[PreOCIModel(), OCIModel(),
|
||||||
SplitModel({'devtable'}, {'buynlarge'})])
|
SplitModel(0, {'devtable'}, {'buynlarge'})])
|
||||||
def registry_model(request, initialized_db):
|
def registry_model(request, initialized_db):
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
|
|
Reference in a new issue