launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24163
[Merge] ~twom/launchpad:oci-registry into launchpad:master
Tom Wardill has proposed merging ~twom/launchpad:oci-registry into launchpad:master with ~twom/launchpad:oci-buildbehaviour as a prerequisite.
Commit message:
Add OCIRegistry model
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/376860
OCI Images need to be pushed somewhere so that they can be retrieved.
This adds a reference to OCIRecipe so that a built recipe can retrieve the details required to push the artifacts.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-registry into launchpad:master.
diff --git a/lib/lp/oci/configure.zcml b/lib/lp/oci/configure.zcml
index 70bb3bc..32150ec 100644
--- a/lib/lp/oci/configure.zcml
+++ b/lib/lp/oci/configure.zcml
@@ -52,6 +52,28 @@
<allow interface="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource" />
</securedutility>
+ <!-- OCIRegistry -->
+ <class
+ class="lp.oci.model.ociregistry.OCIRegistry">
+ <require
+ permission="launchpad.View"
+ interface="lp.oci.interfaces.ociregistry.IOCIRegistryView
+ lp.oci.interfaces.ociregistry.IOCIRegistryEditableAttributes"/>
+ <require
+ permission="launchpad.Edit"
+ interface="lp.oci.interfaces.ociregistry.IOCIRegistryEdit"
+ set_schema="lp.oci.interfaces.ociregistry.IOCIRegistryEditableAttributes" />
+ </class>
+
+ <!-- OCIRegistrySet -->
+ <securedutility
+ class="lp.oci.model.ociregistry.OCIRegistrySet"
+ provides="lp.oci.interfaces.ociregistry.IOCIRegistrySet">
+ <allow
+ interface="lp.oci.interfaces.ociregistry.IOCIRegistrySet"/>
+ </securedutility>
+
+
<adapter
for="lp.oci.interfaces.ocirecipebuild.IOCIRecipeBuild"
provides="lp.buildmaster.interfaces.buildfarmjobbehaviour.IBuildFarmJobBehaviour"
diff --git a/lib/lp/oci/interfaces/ocirecipe.py b/lib/lp/oci/interfaces/ocirecipe.py
index 9532834..7e11fa0 100644
--- a/lib/lp/oci/interfaces/ocirecipe.py
+++ b/lib/lp/oci/interfaces/ocirecipe.py
@@ -37,6 +37,7 @@ from zope.schema import (
from zope.security.interfaces import Unauthorized
from lp import _
+from lp.oci.interfaces.ociregistry import IOCIRegistry
from lp.registry.interfaces.ociproject import IOCIProject
from lp.registry.interfaces.role import IHasOwner
from lp.services.fields import (
@@ -153,6 +154,11 @@ class IOCIRecipeEditableAttributes(IHasOwner):
title=_("Build daily"), required=True, default=False,
description=_("If True, this recipe should be built daily."))
+ registry = Reference(
+ IOCIRegistry,
+ title=_("The OCI registry that builds of "
+ "this recipe should be pushed to."))
+
class IOCIRecipe(IOCIRecipeView, IOCIRecipeEdit, IOCIRecipeEditableAttributes):
"""A recipe for building Open Container Initiative images."""
diff --git a/lib/lp/oci/interfaces/ociregistry.py b/lib/lp/oci/interfaces/ociregistry.py
new file mode 100644
index 0000000..df65ddf
--- /dev/null
+++ b/lib/lp/oci/interfaces/ociregistry.py
@@ -0,0 +1,82 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Interfaces for handling OCI registry details."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'IOCIRegistry',
+ 'IOCIRegistryEdit',
+ 'IOCIRegistryEditableAttributes',
+ 'IOCIRegistryView',
+ 'IOCIRegistrySet',
+]
+
+from zope.interface import Interface
+from zope.schema import (
+ Bool,
+ Datetime,
+ Int,
+ TextLine,
+ )
+
+from lp import _
+from lp.app.validators.name import name_validator
+from lp.app.validators.url import validate_url
+from lp.services.fields import PublicPersonChoice
+
+
+class IOCIRegistryView(Interface):
+ """`IOCIRegistry` attributes that require launchpad.View permission."""
+
+ id = Int(title=_("ID"), required=True, readonly=True)
+ date_created = Datetime(
+ title=_("The date on which this registry was created in Launchpad."),
+ required=True, readonly=True)
+
+ registrant = PublicPersonChoice(
+ title=_("The user who registered this registry."),
+ vocabulary='ValidPersonOrTeam', required=True, readonly=True)
+
+
+class IOCIRegistryEditableAttributes(Interface):
+ """`IOCIRegistry` attributes that can be edited.
+
+ These attributes need launchpad.View to see, and launchpad.Edit to change.
+ """
+
+ name = TextLine(
+ title=_("The name of this registry."),
+ constraint=name_validator,
+ required=True)
+
+ title = TextLine(
+ title=_("A title for this registry."),
+ required=True)
+
+ base_url = TextLine(
+ title=_("The base URL for this registry."),
+ constraint=validate_url,
+ required=True)
+
+ active = Bool(
+ title=_("If True, this registry is active."),
+ required=True, default=True)
+
+
+class IOCIRegistryEdit(Interface):
+ """`IOCIRegistry` methods that require launchpad.Edit permission."""
+
+
+class IOCIRegistry(IOCIRegistryView, IOCIRegistryEditableAttributes,
+ IOCIRegistryEdit):
+ """A registry for Open Container Initiative images."""
+
+
+class IOCIRegistrySet(Interface):
+ """A utility to create and access OCI Registries."""
+
+ def new(registrant, name, title, base_url, active):
+ """Create an IOCIRegistry."""
diff --git a/lib/lp/oci/model/ocirecipe.py b/lib/lp/oci/model/ocirecipe.py
index eaa03c5..d2eab30 100644
--- a/lib/lp/oci/model/ocirecipe.py
+++ b/lib/lp/oci/model/ocirecipe.py
@@ -87,6 +87,9 @@ class OCIRecipe(Storm):
build_daily = Bool(name="build_daily", default=False)
+ registry_id = Int(name="registry")
+ registry = Reference(registry_id, 'OCIRegistry.id')
+
def __init__(self, registrant, owner, ociproject, ociproject_default=False,
require_virtualized=True):
super(OCIRecipe, self).__init__()
diff --git a/lib/lp/oci/model/ociregistry.py b/lib/lp/oci/model/ociregistry.py
new file mode 100644
index 0000000..9d69baa
--- /dev/null
+++ b/lib/lp/oci/model/ociregistry.py
@@ -0,0 +1,67 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""An instance of an OCI Registry."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'OCIRegistry',
+ 'OCIRegistrySet'
+ ]
+
+import pytz
+from storm.locals import (
+ Bool,
+ DateTime,
+ Int,
+ Reference,
+ Storm,
+ Unicode,
+ )
+from zope.interface import implementer
+
+from lp.oci.interfaces.ociregistry import (
+ IOCIRegistry,
+ IOCIRegistrySet,
+ )
+from lp.services.database.interfaces import IMasterStore
+
+
+@implementer(IOCIRegistry)
+class OCIRegistry(Storm):
+
+ __storm_table__ = "OCIRegistry"
+
+ id = Int(primary=True)
+ date_created = DateTime(
+ name="date_created", tzinfo=pytz.UTC, allow_none=False)
+
+ registrant_id = Int(name='registrant', allow_none=False)
+ registrant = Reference(registrant_id, "Person.id")
+
+ name = Unicode(name="name", allow_none=False)
+
+ title = Unicode(name="title", allow_none=False)
+
+ base_url = Unicode(name="base_url", allow_none=False)
+
+ active = Bool(name="active", default=False)
+
+ def __init__(self, registrant, name, title, base_url, active):
+ self.registrant = registrant
+ self.name = name
+ self.title = title
+ self.base_url = base_url
+ self.active = active
+
+
+@implementer(IOCIRegistrySet)
+class OCIRegistrySet:
+
+ def new(self, registrant, name, title, base_url, active):
+ store = IMasterStore(OCIRegistry)
+ oci_registry = OCIRegistry(registrant, name, title, base_url, active)
+ store.add(oci_registry)
+ return oci_registry
diff --git a/lib/lp/oci/tests/test_ociregistry.py b/lib/lp/oci/tests/test_ociregistry.py
new file mode 100644
index 0000000..4f9fbda
--- /dev/null
+++ b/lib/lp/oci/tests/test_ociregistry.py
@@ -0,0 +1,53 @@
+# Copyright 2019 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for OCI image registry handling functionality."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from zope.component import getUtility
+
+from lp.oci.interfaces.ociregistry import (
+ IOCIRegistry,
+ IOCIRegistrySet,
+ )
+from lp.testing import (
+ admin_logged_in,
+ TestCaseWithFactory,
+ )
+from lp.testing.layers import DatabaseFunctionalLayer
+
+
+class TestOCIRegistry(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_implements_interface(self):
+ target = self.factory.makeOCIRegistry()
+ with admin_logged_in():
+ self.assertProvides(target, IOCIRegistry)
+
+
+class TestOCIRegistrySet(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_implements_interface(self):
+ target_set = getUtility(IOCIRegistrySet)
+ with admin_logged_in():
+ self.assertProvides(target_set, IOCIRegistrySet)
+
+ def test_new(self):
+ registrant = self.factory.makePerson()
+ name = self.factory.getUniqueString(u"oci-registry-name")
+ title = self.factory.getUniqueString(u"oci-registry-title")
+ base_url = self.factory.getUniqueURL().decode('utf-8')
+ active = True
+ target = getUtility(IOCIRegistrySet).new(
+ registrant=registrant, name=name, title=title, base_url=base_url,
+ active=active)
+ self.assertEqual(target.registrant, registrant)
+ self.assertEqual(target.name, name)
+ self.assertEqual(target.title, title)
+ self.assertEqual(target.base_url, base_url)
+ self.assertEqual(target.active, active)
diff --git a/lib/lp/security.py b/lib/lp/security.py
index 4e586d1..dee5521 100644
--- a/lib/lp/security.py
+++ b/lib/lp/security.py
@@ -114,6 +114,7 @@ from lp.hardwaredb.interfaces.hwdb import (
)
from lp.oci.interfaces.ocirecipe import IOCIRecipe
from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuild
+from lp.oci.interfaces.ociregistry import IOCIRegistry
from lp.registry.enums import PersonVisibility
from lp.registry.interfaces.announcement import IAnnouncement
from lp.registry.interfaces.distribution import IDistribution
@@ -3472,3 +3473,8 @@ class ViewOCIRecipe(AnonymousAuthorization):
class ViewOCIRecipeBuild(AnonymousAuthorization):
"""Anyone can view an `IOCIRecipe`."""
usedfor = IOCIRecipeBuild
+
+
+class ViewOCIRegistry(AnonymousAuthorization):
+ """Anyone can view an `IOCIRegistry`."""
+ usedfor = IOCIRegistry
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 2cd8adb..f2bc2ed 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -158,6 +158,7 @@ from lp.hardwaredb.interfaces.hwdb import (
IHWSubmissionSet,
)
from lp.oci.interfaces.ocirecipebuild import IOCIRecipeBuildSet
+from lp.oci.interfaces.ociregistry import IOCIRegistrySet
from lp.oci.model.ocirecipe import (
OCIRecipe,
OCIRecipeArch,
@@ -5023,6 +5024,21 @@ class BareLaunchpadObjectFactory(ObjectFactory):
return OCIFile(build=build, library_file=library_file,
layer_file_digest=layer_file_digest)
+ def makeOCIRegistry(self, registrant=None, name=None, title=None,
+ base_url=None, active=True):
+ """Make a new OCIRegistry."""
+ if registrant is None:
+ registrant = self.makePerson()
+ if name is None:
+ name = self.getUniqueString(u"oci-registry-name")
+ if title is None:
+ title = self.getUniqueString(u"oci-registry-title")
+ if base_url is None:
+ base_url = self.getUniqueURL().decode('utf-8')
+ return getUtility(IOCIRegistrySet).new(
+ registrant=registrant, name=name, title=title, base_url=base_url,
+ active=active)
+
# Some factory methods return simple Python types. We don't add
# security wrappers for them, as well as for objects created by
Follow ups