launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26998
[Merge] ~twom/launchpad:oci-set-distribution-credentials-via-api into launchpad:master
Tom Wardill has proposed merging ~twom/launchpad:oci-set-distribution-credentials-via-api into launchpad:master.
Commit message:
Allow setting oci registry credentials on a distribution via the API
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/402084
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-set-distribution-credentials-via-api into launchpad:master.
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
index e5777ec..aa8a74c 100644
--- a/lib/lp/registry/browser/distribution.py
+++ b/lib/lp/registry/browser/distribution.py
@@ -82,9 +82,6 @@ from lp.bugs.browser.structuralsubscription import (
)
from lp.buildmaster.interfaces.processor import IProcessorSet
from lp.code.browser.vcslisting import TargetDefaultVCSNavigationMixin
-from lp.oci.interfaces.ociregistrycredentials import (
- IOCIRegistryCredentialsSet,
- )
from lp.registry.browser import (
add_subscribe_link,
RegistryEditFormView,
diff --git a/lib/lp/registry/interfaces/distribution.py b/lib/lp/registry/interfaces/distribution.py
index 5ec5271..8f43f58 100644
--- a/lib/lp/registry/interfaces/distribution.py
+++ b/lib/lp/registry/interfaces/distribution.py
@@ -14,15 +14,18 @@ __all__ = [
'IDistributionSet',
'NoPartnerArchive',
'NoSuchDistribution',
+ 'NoOCIAdminForDistribution',
]
from lazr.lifecycle.snapshot import doNotSnapshot
from lazr.restful.declarations import (
call_with,
collection_default_content,
+ error_status,
export_factory_operation,
export_operation_as,
export_read_operation,
+ export_write_operation,
exported,
exported_as_webservice_collection,
exported_as_webservice_entry,
@@ -38,6 +41,7 @@ from lazr.restful.fields import (
Reference,
)
from lazr.restful.interface import copy_field
+from six.moves import http_client
from zope.interface import (
Attribute,
Interface,
@@ -113,6 +117,15 @@ from lp.translations.interfaces.hastranslationimports import (
from lp.translations.interfaces.translationpolicy import ITranslationPolicy
+@error_status(http_client.BAD_REQUEST)
+class NoOCIAdminForDistribution(Exception):
+ """There is no OCI Project Admin for this distribution."""
+
+ def __init__(self):
+ super(NoOCIAdminForDistribution, self).__init__(
+ "There is no OCI Project Admin for this distribution.")
+
+
class IDistributionMirrorMenuMarker(Interface):
"""Marker interface for Mirror navigation."""
@@ -129,6 +142,35 @@ class DistributionNameField(PillarNameField):
class IDistributionEditRestricted(IOfficialBugTagTargetRestricted):
"""IDistribution properties requiring launchpad.Edit permission."""
+ @call_with(registrant=REQUEST_USER)
+ @operation_parameters(
+ registry_url=TextLine(
+ title=_("The registry url."),
+ description=_("The url of the OCI registry to use."),
+ required=True),
+ region=TextLine(
+ title=_("OCI registry region."),
+ description=_("The region of the OCI registry."),
+ required=False),
+ username=TextLine(
+ title=_("Username"),
+ description=_("The username for the OCI registry."),
+ required=False),
+ password=TextLine(
+ title=_("Password"),
+ description=_("The password for the OCI registry."),
+ required=False))
+ @export_write_operation()
+ @operation_for_version("devel")
+ def setOCICredentials(registrant, registry_url, region,
+ username, password):
+ """Set the credentials for the OCI registry for OCI projects."""
+
+ @export_write_operation()
+ @operation_for_version("devel")
+ def deleteOCICredentials():
+ """Delete any existing OCI credentials for the distribution."""
+
class IDistributionDriverRestricted(Interface):
"""IDistribution properties requiring launchpad.Driver permission."""
@@ -727,7 +769,6 @@ class IDistributionPublic(
"images in this distribution to a registry."),
required=False, readonly=False)
-
@exported_as_webservice_entry(as_of="beta")
class IDistribution(
IDistributionEditRestricted, IDistributionPublic, IHasBugSupervisor,
diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
index 0288c54..f76d28b 100644
--- a/lib/lp/registry/model/distribution.py
+++ b/lib/lp/registry/model/distribution.py
@@ -89,6 +89,7 @@ from lp.bugs.model.structuralsubscription import (
from lp.code.interfaces.seriessourcepackagebranch import (
IFindOfficialBranchLinks,
)
+from lp.oci.interfaces.ociregistrycredentials import IOCIRegistryCredentialsSet
from lp.registry.enums import (
BranchSharingPolicy,
BugSharingPolicy,
@@ -101,6 +102,7 @@ from lp.registry.interfaces.accesspolicy import IAccessPolicySource
from lp.registry.interfaces.distribution import (
IDistribution,
IDistributionSet,
+ NoOCIAdminForDistribution,
)
from lp.registry.interfaces.distributionmirror import (
IDistributionMirror,
@@ -1531,6 +1533,32 @@ class Distribution(SQLBase, BugTargetBase, MakesAnnouncements,
pillar=self, registrant=registrant, name=name,
description=description)
+ def setOCICredentials(self, registrant, registry_url,
+ region, username, password):
+ """See `IDistribution`."""
+ if not self.oci_project_admin:
+ raise NoOCIAdminForDistribution()
+ new_credentials = getUtility(IOCIRegistryCredentialsSet).getOrCreate(
+ registrant,
+ self.oci_project_admin,
+ registry_url,
+ {"username": username, "password": password, "region": region},
+ override_owner=True)
+ old_credentials = self.oci_registry_credentials
+ if self.oci_registry_credentials != new_credentials:
+ # Remove the old credentials as we're assigning new ones
+ # or clearing them
+ self.oci_registry_credentials = new_credentials
+ if old_credentials:
+ old_credentials.destroySelf()
+
+ def deleteOCICredentials(self):
+ """See `IDistribution`."""
+ old_credentials = self.oci_registry_credentials
+ if old_credentials:
+ self.oci_registry_credentials = None
+ old_credentials.destroySelf()
+
@implementer(IDistributionSet)
class DistributionSet:
diff --git a/lib/lp/registry/tests/test_distribution.py b/lib/lp/registry/tests/test_distribution.py
index 0b9f712..44defc1 100644
--- a/lib/lp/registry/tests/test_distribution.py
+++ b/lib/lp/registry/tests/test_distribution.py
@@ -28,6 +28,7 @@ from lp.app.enums import (
)
from lp.app.errors import NotFoundError
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
+from lp.oci.tests.helpers import OCIConfigHelperMixin
from lp.registry.enums import (
BranchSharingPolicy,
BugSharingPolicy,
@@ -761,7 +762,7 @@ class DistributionOCIProjectAdminPermission(TestCaseWithFactory):
self.assertTrue(distro.canAdministerOCIProjects(admin))
-class TestDistributionWebservice(TestCaseWithFactory):
+class TestDistributionWebservice(OCIConfigHelperMixin, TestCaseWithFactory):
"""Test the IDistribution API.
Some tests already exist in xx-distribution.txt.
@@ -842,3 +843,83 @@ class TestDistributionWebservice(TestCaseWithFactory):
start_date=(now - day).isoformat(),
end_date=now.isoformat())
self.assertEqual([], empty_response.jsonBody())
+
+ def test_setOCICredentials(self):
+ # We can add OCI Credentials to the distribution
+ self.setConfig()
+ with person_logged_in(self.person):
+ distro = self.factory.makeDistribution(owner=self.person)
+ distro.oci_project_admin = self.person
+ distro_url = api_url(distro)
+
+ resp = self.webservice.named_post(
+ distro_url,
+ "setOCICredentials",
+ registry_url="http://registry.test",
+ )
+
+ self.assertEqual(200, resp.status)
+ with person_logged_in(self.person):
+ self.assertEqual(
+ "http://registry.test",
+ distro.oci_registry_credentials.url
+ )
+
+ def test_setOCICredentials_no_oci_admin(self):
+ # If there's no oci_project_admin to own the credentials, error
+ self.setConfig()
+ with person_logged_in(self.person):
+ distro = self.factory.makeDistribution(owner=self.person)
+ distro_url = api_url(distro)
+
+ resp = self.webservice.named_post(
+ distro_url,
+ "setOCICredentials",
+ registry_url="http://registry.test",
+ )
+
+ self.assertEqual(400, resp.status)
+ self.assertIn(
+ b"no OCI Project Admin for this distribution",
+ resp.body)
+
+ def test_setOCICredentials_changes_credentials(self):
+ # if we have existing credentials, we should change them
+ self.setConfig()
+ with person_logged_in(self.person):
+ distro = self.factory.makeDistribution(owner=self.person)
+ distro.oci_project_admin = self.person
+ credentials = self.factory.makeOCIRegistryCredentials()
+ distro.oci_registry_credentials = credentials
+ distro_url = api_url(distro)
+
+ resp = self.webservice.named_post(
+ distro_url,
+ "setOCICredentials",
+ registry_url="http://registry.test",
+ )
+
+ self.assertEqual(200, resp.status)
+ with person_logged_in(self.person):
+ self.assertEqual(
+ "http://registry.test",
+ distro.oci_registry_credentials.url
+ )
+
+ def test_deleteOCICredentials(self):
+ # We can remove existing credentials
+ self.setConfig()
+ with person_logged_in(self.person):
+ distro = self.factory.makeDistribution(owner=self.person)
+ distro.oci_project_admin = self.person
+ credentials = self.factory.makeOCIRegistryCredentials()
+ distro.oci_registry_credentials = credentials
+ distro_url = api_url(distro)
+
+ resp = self.webservice.named_post(
+ distro_url,
+ "deleteOCICredentials")
+
+ self.assertEqual(200, resp.status)
+ with person_logged_in(self.person):
+ self.assertIsNone(distro.oci_registry_credentials)
Follow ups