launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15669
[Merge] lp:~stevenk/launchpad/das-setchroot-api into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/das-setchroot-api into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/das-setchroot-api/+merge/167464
Add a new API, IDistroArchSeries.setChroot() which allows owners of the relevant main_archive to upload chroots using the API.
--
https://code.launchpad.net/~stevenk/launchpad/das-setchroot-api/+merge/167464
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/das-setchroot-api into lp:launchpad.
=== modified file 'lib/lp/security.py'
--- lib/lp/security.py 2013-05-10 06:28:17 +0000
+++ lib/lp/security.py 2013-06-05 06:47:44 +0000
@@ -1346,6 +1346,16 @@
usedfor = IDistroArchSeries
+class EditDistroArchSeries(AuthorizationBase):
+ permission = 'launchpad.Edit'
+ usedfor = IDistroArchSeries
+
+ def checkAuthenticated(self, user):
+ return (
+ user.isOwner(self.obj.distroseries.distribution.main_archive)
+ or user.in_admin)
+
+
class ViewAnnouncement(AuthorizationBase):
permission = 'launchpad.View'
usedfor = IAnnouncement
=== modified file 'lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py'
--- lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py 2012-01-01 02:58:52 +0000
+++ lib/lp/soyuz/browser/tests/test_distroarchseries_webservice.py 2013-06-05 06:47:44 +0000
@@ -1,8 +1,14 @@
-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
+import hashlib
+
+from lazr.restfulclient.errors import (
+ BadRequest,
+ Unauthorized,
+ )
from zope.security.management import endInteraction
from lp.testing import (
@@ -10,13 +16,13 @@
TestCaseWithFactory,
ws_object,
)
-from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.layers import LaunchpadFunctionalLayer
class TestDistroArchSeriesWebservice(TestCaseWithFactory):
"""Unit Tests for 'DistroArchSeries' Webservice.
"""
- layer = DatabaseFunctionalLayer
+ layer = LaunchpadFunctionalLayer
def _makeDistroArchSeries(self):
"""Create a `DistroSeries` object, that is prefilled with 1
@@ -38,8 +44,8 @@
endInteraction()
launchpad = launchpadlib_for('test', person=None, version='devel')
ws_distroseries = ws_object(launchpad, distroseries)
- #Note, we test the length of architectures.entries, not
- #architectures due to the removal of the entries by lazr
+ # Note, we test the length of architectures.entries, not
+ # architectures due to the removal of the entries by lazr
self.assertEqual(1, len(ws_distroseries.architectures.entries))
def test_distroseries_architectures_authenticated(self):
@@ -51,3 +57,33 @@
ws_distroseries = ws_object(launchpad, distroseries)
#See note above regarding testing of length of .entries
self.assertEqual(1, len(ws_distroseries.architectures.entries))
+
+ def test_setChroot_random_user(self):
+ # Random users are not allowed to set chroots.
+ das = self.factory.makeDistroArchSeries()
+ user = self.factory.makePerson()
+ webservice = launchpadlib_for("testing", user, version='devel')
+ ws_das = ws_object(webservice, das)
+ self.assertRaises(
+ Unauthorized, ws_das.setChroot, data='xyz',sha1sum='0')
+
+ def test_setChroot_wrong_sha1sum(self):
+ # If the sha1sum calculated is different, the chroot is not set.
+ das = self.factory.makeDistroArchSeries()
+ user = das.distroseries.distribution.main_archive.owner
+ webservice = launchpadlib_for("testing", user)
+ ws_das = ws_object(webservice, das)
+ self.assertRaises(
+ BadRequest, ws_das.setChroot, data='zyx', sha1sum='x')
+
+ def test_setChroot(self):
+ das = self.factory.makeDistroArchSeries()
+ user = das.distroseries.distribution.main_archive.owner
+ expected_file = 'chroot-%s-%s-%s.tar.bz2' % (
+ das.distroseries.distribution.name, das.distroseries.name,
+ das.architecturetag)
+ webservice = launchpadlib_for("testing", user)
+ ws_das = ws_object(webservice, das)
+ sha1 = hashlib.sha1('abcxyz').hexdigest()
+ ws_das.setChroot(data='abcxyz', sha1sum=sha1)
+ self.assertTrue(ws_das.chroot_url.endswith(expected_file))
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2013-05-24 01:28:22 +0000
+++ lib/lp/soyuz/configure.zcml 2013-06-05 06:47:44 +0000
@@ -617,14 +617,17 @@
<class
class="lp.soyuz.model.distroarchseries.DistroArchSeries">
<allow
- interface="lp.soyuz.interfaces.distroarchseries.IDistroArchSeries"/>
+ interface="lp.soyuz.interfaces.distroarchseries.IDistroArchSeriesPublic"/>
<allow
interface="lp.soyuz.interfaces.buildrecords.IHasBuildRecords"/>
<allow
interface="lp.soyuz.interfaces.publishing.ICanPublishPackages"/>
<require
permission="launchpad.Admin"
- set_schema="lp.soyuz.interfaces.distroarchseries.IDistroArchSeries"/>
+ set_schema="lp.soyuz.interfaces.distroarchseries.IDistroArchSeriesPublic"/>
+ <require
+ permission="launchpad.Edit"
+ interface="lp.soyuz.interfaces.distroarchseries.IDistroArchSeriesEdit"/>
</class>
<adapter
for="lp.soyuz.interfaces.distroarchseries.IDistroArchSeries"
=== modified file 'lib/lp/soyuz/interfaces/distroarchseries.py'
--- lib/lp/soyuz/interfaces/distroarchseries.py 2013-05-01 18:29:52 +0000
+++ lib/lp/soyuz/interfaces/distroarchseries.py 2013-06-05 06:47:44 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Distribution architecture series interfaces."""
@@ -7,12 +7,19 @@
__all__ = [
'IDistroArchSeries',
+ 'InvalidChrootUploaded',
'IPocketChroot',
]
+import httplib
+
from lazr.restful.declarations import (
+ error_status,
export_as_webservice_entry,
+ export_write_operation,
exported,
+ operation_for_version,
+ operation_parameters,
)
from lazr.restful.fields import Reference
from zope.interface import (
@@ -21,8 +28,10 @@
)
from zope.schema import (
Bool,
+ Bytes,
Choice,
Int,
+ Text,
TextLine,
)
@@ -33,9 +42,13 @@
from lp.registry.interfaces.role import IHasOwner
-class IDistroArchSeries(IHasOwner):
- """DistroArchSeries Table Interface"""
- export_as_webservice_entry()
+@error_status(httplib.BAD_REQUEST)
+class InvalidChrootUploaded(Exception):
+ """Raised when the sha1sum of an uploaded chroot does not match."""
+
+
+class IDistroArchSeriesPublic(IHasOwner):
+ """Public attributes for a DistroArchSeries."""
id = Attribute("Identifier")
distroseries = exported(
@@ -185,18 +198,30 @@
this distro arch series.
"""
+class IDistroArchSeriesEdit(Interface):
+
+ @operation_parameters(data=Bytes(), sha1sum=Text())
+ @export_write_operation()
+ @operation_for_version("devel")
+ def setChroot(data, sha1sum):
+ """Upload a new chroot, compare the computed checksum against the
+ provided value, and if they match, set the `IPocketChroot` to the new
+ value.
+ """
+
+
+class IDistroArchSeries(IDistroArchSeriesPublic, IDistroArchSeriesEdit):
+ """An architecture for a distroseries."""
+ export_as_webservice_entry()
+
class IPocketChroot(Interface):
"""PocketChroot Table Interface"""
id = Attribute("Identifier")
- distroarchseries = Attribute("The DistroArchSeries this chroot "
- "belongs to.")
+ distroarchseries = Attribute(
+ "The DistroArchSeries this chroot belongs to.")
pocket = Attribute("The Pocket this chroot is for.")
chroot = Attribute("The file alias of the chroot.")
def syncUpdate():
"""Commit changes to DB."""
-
-
-# Monkey patching circular import fixes is done in
-# _schema_circular_imports.py
=== modified file 'lib/lp/soyuz/model/distroarchseries.py'
--- lib/lp/soyuz/model/distroarchseries.py 2013-02-06 09:22:35 +0000
+++ lib/lp/soyuz/model/distroarchseries.py 2013-06-05 06:47:44 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -7,6 +7,8 @@
'PocketChroot'
]
+from cStringIO import StringIO
+
from sqlobject import (
BoolCol,
ForeignKey,
@@ -39,12 +41,17 @@
sqlvalues,
)
from lp.services.helpers import shortlist
+from lp.services.librarian.interfaces import ILibraryFileAliasSet
+from lp.services.webapp.publisher import (
+ get_raw_form_value_from_current_request,
+ )
from lp.soyuz.enums import PackagePublishingStatus
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
from lp.soyuz.interfaces.binarypackagename import IBinaryPackageName
from lp.soyuz.interfaces.buildrecords import IHasBuildRecords
from lp.soyuz.interfaces.distroarchseries import (
IDistroArchSeries,
+ InvalidChrootUploaded,
IPocketChroot,
)
from lp.soyuz.interfaces.publishing import ICanPublishPackages
@@ -166,6 +173,23 @@
return pocket_chroot
+ def setChroot(self, data, sha1sum):
+ """See `IDistroArchSeries`."""
+ data = get_raw_form_value_from_current_request('data')
+ if isinstance(data, str):
+ filecontent = data
+ else:
+ filecontent = data.read()
+ filename = 'chroot-%s-%s-%s.tar.bz2' % (
+ self.distroseries.distribution.name, self.distroseries.name,
+ self.architecturetag)
+ lfa = getUtility(ILibraryFileAliasSet).create(
+ name=filename, size=len(filecontent), file=StringIO(filecontent),
+ contentType='application/octet-stream')
+ if lfa.content.sha1 != sha1sum:
+ raise InvalidChrootUploaded("Chroot upload checksums do not match")
+ self.addOrUpdateChroot(lfa)
+
def searchBinaryPackages(self, text):
"""See `IDistroArchSeries`."""
from lp.soyuz.model.publishing import BinaryPackagePublishingHistory