launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24155
[Merge] ~twom/launchpad:oci-buildjob into launchpad:master
Tom Wardill has proposed merging ~twom/launchpad:oci-buildjob into launchpad:master with ~twom/launchpad:oci-ocirecipebuild as a prerequisite.
Commit message:
OCIRecipeBuildJob support
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/376475
Derive a new type of BuildJob and use it to build and upload OCI Recipe artifacts
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-buildjob into launchpad:master.
diff --git a/lib/lp/oci/interfaces/ocirecipebuildjob.py b/lib/lp/oci/interfaces/ocirecipebuildjob.py
new file mode 100644
index 0000000..d28c3e8
--- /dev/null
+++ b/lib/lp/oci/interfaces/ocirecipebuildjob.py
@@ -0,0 +1,38 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""OCIRecipe build job interfaces"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'IOCIRecipeBuildJob',
+ ]
+
+from lazr.restful.fields import Reference
+from zope.interface import (
+ Attribute,
+ Interface
+ )
+from zope.schema import TextLine
+
+from lp import _
+from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuild
+from lp.services.job.interfaces.job import (
+ IJob,
+ IJobSource,
+ IRunnableJob
+ )
+
+
+class IOCIRecipeBuildJob(Interface):
+ job = Reference(
+ title=_("The common Job attributes."), schema=IJob,
+ required=True, readonly=True)
+
+ build = Reference(
+ title=_("The OCI Recipe Build to use for this job."),
+ schema=IOCIRecipeBuild, required=True, readonly=True)
+
+ json_data = Attribute(_("A dict of data about the job."))
diff --git a/lib/lp/oci/model/ocirecipebuildjob.py b/lib/lp/oci/model/ocirecipebuildjob.py
new file mode 100644
index 0000000..5491e3d
--- /dev/null
+++ b/lib/lp/oci/model/ocirecipebuildjob.py
@@ -0,0 +1,143 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""OCIRecipe build jobs."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'OCIRecipeBuildJob',
+ ]
+
+import json
+
+from lazr.delegates import delegate_to
+from lazr.enum import (
+ DBEnumeratedType,
+ DBItem,
+ )
+from storm.locals import (
+ Int,
+ JSON,
+ Reference,
+ )
+from zope.interface import (
+ implementer,
+ provider,
+ )
+
+from lp.app.errors import NotFoundError
+from lp.oci.interfaces.ocirecipebuildjob import (
+ IOCIRecipeBuildJob,
+ )
+from lp.services.database.enumcol import EnumCol
+from lp.services.database.interfaces import (
+ IMasterStore,
+ IStore,
+ )
+from lp.services.database.stormbase import StormBase
+from lp.services.propertycache import get_property_cache
+from lp.services.job.model.job import (
+ EnumeratedSubclass,
+ Job,
+ )
+from lp.services.job.runner import BaseRunnableJob
+
+
+class OCIRecipeBuildJobType(DBEnumeratedType):
+ """Values that `OCIBuildJobType.job_type` can take."""
+
+ REGISTRY_UPLOAD = DBItem(0, """
+ Registry upload
+
+ This job uploads an OCI Image to registry.
+ """)
+
+
+@implementer(IOCIRecipeBuildJob)
+class OCIRecipeBuildJob(StormBase):
+ """See `IOCIRecipeBuildJob`."""
+
+ __storm_table__ = 'OCIRecipeBuildJob'
+
+ job_id = Int(name='job', primary=True, allow_none=False)
+ job = Reference(job_id, 'Job.id')
+
+ build_id = Int(name='build', allow_none=False)
+ build = Reference(build_id, 'OCIRecipeBuild.id')
+
+ job_type = EnumCol(enum=OCIRecipeBuildJobType, notNull=True)
+
+ metadata = JSON('json_data', allow_none=False)
+
+ def __init__(self, build, job_type, json_data, **job_args):
+ """Constructor.
+
+ Extra keyword arguments are used to construct the underlying Job
+ object.
+
+ :param build: The `IOCIRecipeBuild` this job relates to.
+ :param job_type: The `OCIRecipeBuildJobType` of this job.
+ :param json_data: The type-specific variables, as a JSON-compatible
+ dict.
+ """
+ super(OCIRecipeBuildJob, self).__init__()
+ self.job = Job(**job_args)
+ self.build = build
+ self.job_type = job_type
+ self.json_data = json_data
+
+ def makeDerived(self):
+ return OCIRecipeBuildJob.makeSubclass(self)
+
+
+@delegate_to(IOCIRecipeBuildJob)
+class OCIRecipeBuildJobDerived(BaseRunnableJob):
+
+ __metaclass__ = EnumeratedSubclass
+
+ def __init__(self, oci_build_job):
+ self.context = oci_build_job
+
+ def __repr__(self):
+ """An informative representation of the job."""
+ return "<%s for %s>" % (
+ self.__class__.__name__, self.build.id)
+
+ @classmethod
+ def get(cls, job_id):
+ """Get a job by id.
+
+ :return: The `OCIBuildJob` with the specified id, as the current
+ `OCIBuildJobDerived` subclass.
+ :raises: `NotFoundError` if there is no job with the specified id,
+ or its `job_type` does not match the desired subclass.
+ """
+ oci_build_job = IStore(OCIRecipeBuildJob).get(
+ OCIRecipeBuildJob, job_id)
+ if oci_build_job.job_type != cls.class_job_type:
+ raise NotFoundError(
+ "No object found with id %d and type %s" %
+ (job_id, cls.class_job_type.title))
+ return cls(oci_build_job)
+
+ @classmethod
+ def iterReady(cls):
+ """See `IJobSource`."""
+ jobs = IMasterStore(OCIRecipeBuildJob).find(
+ OCIRecipeBuildJob,
+ OCIRecipeBuildJob.job_type == cls.class_job_type,
+ OCIRecipeBuildJob.job == Job.id,
+ Job.id.is_in(Job.ready_jobs))
+ return (cls(job) for job in jobs)
+
+ def getOopsVars(self):
+ """See `IRunnableJob`."""
+ oops_vars = super(OCIRecipeBuildJobDerived, self).getOopsVars()
+ oops_vars.extend([
+ ('job_id', self.context.job.id),
+ ('job_type', self.context.job_type.title),
+ ('build_id', self.context.ocibuild.id),
+ ])
+ return oops_vars
diff --git a/lib/lp/oci/tests/test_ocirecipebuildjob.py b/lib/lp/oci/tests/test_ocirecipebuildjob.py
new file mode 100644
index 0000000..2501f0a
--- /dev/null
+++ b/lib/lp/oci/tests/test_ocirecipebuildjob.py
@@ -0,0 +1,29 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""OCIRecipeBuildJob tests"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+
+
+from lp.oci.interfaces.ocirecipebuildjob import IOCIRecipeBuildJob
+from lp.oci.model.ocirecipebuildjob import (
+ OCIRecipeBuildJob,
+ OCIRecipeBuildJobType,
+ )
+from lp.testing import TestCaseWithFactory
+from lp.testing.layers import DatabaseFunctionalLayer
+
+
+class TestOCIRecipeBuildJob(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_provides_interface(self):
+ oci_build = self.factory.makeOCIRecipeBuild()
+ self.assertProvides(
+ OCIRecipeBuildJob(
+ oci_build, OCIRecipeBuildJobType.REGISTRY_UPLOAD, {}),
+ IOCIRecipeBuildJob)
References