Change build component labeling to use new registry interface

This commit is contained in:
Joseph Schorr 2018-08-17 16:45:27 -04:00
parent b096e793fd
commit 9f96e595ac
6 changed files with 121 additions and 17 deletions

View file

@ -17,9 +17,10 @@ from buildman.jobutil.buildstatus import StatusHandler
from buildman.jobutil.workererror import WorkerError from buildman.jobutil.workererror import WorkerError
from app import app from app import app
from data import model
from data.database import BUILD_PHASE, UseThenDisconnect from data.database import BUILD_PHASE, UseThenDisconnect
from data.model import InvalidRepositoryBuildException from data.model import InvalidRepositoryBuildException
from data.registry_model import registry_model
from data.registry_model.datatypes import RepositoryReference
from util import slash_join from util import slash_join
HEARTBEAT_DELTA = datetime.timedelta(seconds=60) HEARTBEAT_DELTA = datetime.timedelta(seconds=60)
@ -29,6 +30,9 @@ INITIAL_TIMEOUT = 25
SUPPORTED_WORKER_VERSIONS = ['0.3'] SUPPORTED_WORKER_VERSIONS = ['0.3']
# Label which marks a manifest with its source build ID.
INTERNAL_LABEL_BUILD_UUID = 'quay.build.uuid'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ComponentStatus(object): class ComponentStatus(object):
@ -357,18 +361,17 @@ class BuildComponent(BaseComponent):
# Label the pushed manifests with the build metadata. # Label the pushed manifests with the build metadata.
manifest_digests = kwargs.get('digests') or [] manifest_digests = kwargs.get('digests') or []
for digest in manifest_digests: repository = registry_model.lookup_repository(self._current_job.namespace,
with UseThenDisconnect(app.config): self._current_job.repo_name)
try: if repository is not None:
manifest = model.tag.load_manifest_by_digest(self._current_job.namespace, for digest in manifest_digests:
self._current_job.repo_name, digest) with UseThenDisconnect(app.config):
model.label.create_manifest_label(manifest, model.label.INTERNAL_LABEL_BUILD_UUID, manifest = registry_model.lookup_manifest_by_digest(repository, digest)
build_id, 'internal', 'text/plain') if manifest is None:
except model.InvalidManifestException: continue
logger.debug('Could not find built manifest with digest %s under repo %s/%s for build %s',
digest, self._current_job.namespace, self._current_job.repo_name, registry_model.create_manifest_label(manifest, INTERNAL_LABEL_BUILD_UUID,
build_id) build_id, 'internal', 'text/plain')
continue
# Send the notification that the build has completed successfully. # Send the notification that the build has completed successfully.
self._current_job.send_notification('build_success', self._current_job.send_notification('build_success',

View file

@ -11,9 +11,6 @@ from util.validation import is_json
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Label which marks a manifest with its source build ID.
INTERNAL_LABEL_BUILD_UUID = 'quay.build.uuid'
@lru_cache(maxsize=1) @lru_cache(maxsize=1)
def get_label_source_types(): def get_label_source_types():

View file

@ -7,6 +7,9 @@ class RepositoryReference(object):
@classmethod @classmethod
def for_repo_obj(cls, repo_obj): def for_repo_obj(cls, repo_obj):
if repo_obj is None:
return None
return RepositoryReference(repo_obj.id) return RepositoryReference(repo_obj.id)
@ -18,3 +21,13 @@ class Tag(namedtuple('Tag', ['id', 'name'])):
return None return None
return Tag(id=repository_tag.id, name=repository_tag.name) return Tag(id=repository_tag.id, name=repository_tag.name)
class Manifest(namedtuple('Manifest', ['id', 'digest'])):
""" Manifest represents a manifest in a repository. """
@classmethod
def for_tag_manifest(cls, tag_manifest):
if tag_manifest is None:
return None
return Manifest(id=tag_manifest.id, digest=tag_manifest.digest)

View file

@ -19,3 +19,21 @@ class RegistryDataInterface(object):
""" Returns the most recently pushed alive tag in the repository, if any. If none, returns """ Returns the most recently pushed alive tag in the repository, if any. If none, returns
None. None.
""" """
@abstractmethod
def lookup_repository(self, namespace_name, repo_name, kind_filter=None):
""" Looks up and returns a reference to the repository with the given namespace and name,
or None if none. """
@abstractmethod
def get_manifest_for_tag(self, tag):
""" Returns the manifest associated with the given tag. """
@abstractmethod
def lookup_manifest_by_digest(self, repository_ref, manifest_digest, allow_dead=False):
""" Looks up the manifest with the given digest under the given repository and returns it
or None if none. """
@abstractmethod
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
""" Creates a label on the manifest with the given key and value. """

View file

@ -1,6 +1,7 @@
from data import database
from data import model from data import model
from data.registry_model.interface import RegistryDataInterface from data.registry_model.interface import RegistryDataInterface
from data.registry_model.datatypes import Tag from data.registry_model.datatypes import Tag, RepositoryReference, Manifest
class PreOCIModel(RegistryDataInterface): class PreOCIModel(RegistryDataInterface):
@ -23,5 +24,41 @@ class PreOCIModel(RegistryDataInterface):
found_tag = model.tag.get_most_recent_tag(repository_ref.repo_id) found_tag = model.tag.get_most_recent_tag(repository_ref.repo_id)
return Tag.for_repository_tag(found_tag) return Tag.for_repository_tag(found_tag)
def lookup_repository(self, namespace_name, repo_name, kind_filter=None):
""" Looks up and returns a reference to the repository with the given namespace and name,
or None if none. """
repo = model.repository.get_repository(namespace_name, repo_name, kind_filter=kind_filter)
return RepositoryReference.for_repo_obj(repo)
def get_manifest_for_tag(self, tag):
""" Returns the manifest associated with the given tag. """
try:
tag_manifest = database.TagManifest.get(tag_id=tag.id)
except database.TagManifest.DoesNotExist:
return
return Manifest.for_tag_manifest(tag_manifest)
def lookup_manifest_by_digest(self, repository_ref, manifest_digest, allow_dead=False):
""" Looks up the manifest with the given digest under the given repository and returns it
or None if none. """
repo = model.repository.lookup_repository(repository_ref.repo_id)
if repo is None:
return None
tag_manifest = model.tag.load_manifest_by_digest(repo.namespace_user.username,
repo.name,
manifest_digest, allow_dead=allow_dead)
return Manifest.for_tag_manifest(tag_manifest)
def create_manifest_label(self, manifest, key, value, source_type_name, media_type_name=None):
""" Creates a label on the manifest with the given key and value. """
try:
tag_manifest = database.TagManifest.get(id=manifest.id)
except database.TagManifest.DoesNotExist:
return
model.label.create_manifest_label(tag_manifest, key, value, source_type_name, media_type_name)
pre_oci_model = PreOCIModel() pre_oci_model = PreOCIModel()

View file

@ -39,3 +39,39 @@ def test_get_most_recent_tag(repo_namespace, repo_name, expected, pre_oci_model)
assert found is None assert found is None
else: else:
assert found.name in expected assert found.name in expected
@pytest.mark.parametrize('repo_namespace, repo_name, expected', [
('devtable', 'simple', True),
('buynlarge', 'orgrepo', True),
('buynlarge', 'unknownrepo', False),
])
def test_lookup_repository(repo_namespace, repo_name, expected, pre_oci_model):
repo_ref = pre_oci_model.lookup_repository(repo_namespace, repo_name)
if expected:
assert repo_ref
else:
assert repo_ref is None
@pytest.mark.parametrize('repo_namespace, repo_name', [
('devtable', 'simple'),
('buynlarge', 'orgrepo'),
])
def test_lookup_manifests(repo_namespace, repo_name, pre_oci_model):
repo = model.repository.get_repository(repo_namespace, repo_name)
repository_ref = RepositoryReference.for_repo_obj(repo)
found_tag = pre_oci_model.find_matching_tag(repository_ref, ['latest'])
found_manifest = pre_oci_model.get_manifest_for_tag(found_tag)
found = pre_oci_model.lookup_manifest_by_digest(repository_ref, found_manifest.digest)
assert found.id == found_manifest.id
assert found.digest == found_manifest.digest
def test_create_manifest_label(pre_oci_model):
repo = model.repository.get_repository('devtable', 'simple')
repository_ref = RepositoryReference.for_repo_obj(repo)
found_tag = pre_oci_model.find_matching_tag(repository_ref, ['latest'])
found_manifest = pre_oci_model.get_manifest_for_tag(found_tag)
pre_oci_model.create_manifest_label(found_manifest, 'foo', 'bar', 'internal')