Merge lp:~wgrant/launchpad/builderset-new-api into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 16986
Proposed branch: lp:~wgrant/launchpad/builderset-new-api
Merge into: lp:launchpad
Diff against target: 189 lines (+64/-21)
5 files modified
lib/lp/buildmaster/configure.zcml (+3/-0)
lib/lp/buildmaster/doc/builder.txt (+4/-2)
lib/lp/buildmaster/interfaces/builder.py (+23/-15)
lib/lp/buildmaster/tests/test_webservice.py (+30/-1)
lib/lp/testing/factory.py (+4/-3)
To merge this branch: bzr merge lp:~wgrant/launchpad/builderset-new-api
Reviewer Review Type Date Requested Status
Celso Providelo (community) Approve
Review via email: mp+216861@code.launchpad.net

Commit message

Export BuilderSet.new() on the webservice.

Description of the change

Export BuilderSet.new() on the webservice. All pretty trivial, except for moving BuilderSet.new to a new interface restricted by launchpad.Admin like the view.

To post a comment you must log in.
Revision history for this message
Celso Providelo (cprov) wrote :

Looks good!

It seems to be a good compromise before re-thinking the buildmaster component for the Cloud(tm). However, since we do not have a remove() builders should be created with caution, even by Administrators.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/buildmaster/configure.zcml'
--- lib/lp/buildmaster/configure.zcml 2013-11-20 17:10:19 +0000
+++ lib/lp/buildmaster/configure.zcml 2014-04-23 11:07:46 +0000
@@ -29,6 +29,9 @@
29 provides="lp.buildmaster.interfaces.builder.IBuilderSet">29 provides="lp.buildmaster.interfaces.builder.IBuilderSet">
30 <allow30 <allow
31 interface="lp.buildmaster.interfaces.builder.IBuilderSet"/>31 interface="lp.buildmaster.interfaces.builder.IBuilderSet"/>
32 <require
33 permission="launchpad.Admin"
34 interface="lp.buildmaster.interfaces.builder.IBuilderSetAdmin"/>
32 </securedutility>35 </securedutility>
33 <adapter36 <adapter
34 provides="lp.services.webapp.interfaces.IBreadcrumb"37 provides="lp.services.webapp.interfaces.IBreadcrumb"
3538
=== modified file 'lib/lp/buildmaster/doc/builder.txt'
--- lib/lp/buildmaster/doc/builder.txt 2013-11-28 12:23:01 +0000
+++ lib/lp/buildmaster/doc/builder.txt 2014-04-23 11:07:46 +0000
@@ -69,8 +69,10 @@
6969
70The 'new' method will create a new builder in the database.70The 'new' method will create a new builder in the database.
7171
72 >>> bnew = builderset.new(72 >>> from lp.testing import admin_logged_in
73 ... [1], 'http://dummy.com:8221/', 'dummy', 'Dummy Title', 1)73 >>> with admin_logged_in():
74 ... bnew = builderset.new(
75 ... [1], 'http://dummy.com:8221/', 'dummy', 'Dummy Title', 1)
74 >>> bnew.name76 >>> bnew.name
75 u'dummy'77 u'dummy'
7678
7779
=== modified file 'lib/lp/buildmaster/interfaces/builder.py'
--- lib/lp/buildmaster/interfaces/builder.py 2013-11-28 08:51:32 +0000
+++ lib/lp/buildmaster/interfaces/builder.py 2014-04-23 11:07:46 +0000
@@ -17,15 +17,18 @@
17 ]17 ]
1818
19from lazr.restful.declarations import (19from lazr.restful.declarations import (
20 call_with,
20 collection_default_content,21 collection_default_content,
21 export_as_webservice_collection,22 export_as_webservice_collection,
22 export_as_webservice_entry,23 export_as_webservice_entry,
24 export_factory_operation,
23 export_read_operation,25 export_read_operation,
24 exported,26 exported,
25 operation_for_version,27 operation_for_version,
26 operation_parameters,28 operation_parameters,
27 operation_returns_collection_of,29 operation_returns_collection_of,
28 operation_returns_entry,30 operation_returns_entry,
31 REQUEST_USER,
29 )32 )
30from lazr.restful.fields import (33from lazr.restful.fields import (
31 Reference,34 Reference,
@@ -165,7 +168,7 @@
165 'buildd-slave, e.g.: foobar-host.ppa')))168 'buildd-slave, e.g.: foobar-host.ppa')))
166169
167 active = exported(Bool(170 active = exported(Bool(
168 title=_('Publicly Visible'), required=True, default=True,171 title=_('Publicly Visible'), required=False, default=True,
169 description=_('Whether or not to present the builder publicly.')))172 description=_('Whether or not to present the builder publicly.')))
170173
171 currentjob = Attribute("BuildQueue instance for job being processed.")174 currentjob = Attribute("BuildQueue instance for job being processed.")
@@ -210,7 +213,25 @@
210 """213 """
211214
212215
213class IBuilderSet(Interface):216class IBuilderSetAdmin(Interface):
217
218 @call_with(owner=REQUEST_USER)
219 @export_factory_operation(
220 IBuilder,
221 ['processors', 'url', 'name', 'title', 'active', 'virtualized',
222 'vm_host'])
223 @operation_for_version('devel')
224 def new(processors, url, name, title, owner, active=True,
225 virtualized=False, vm_host=None):
226 """Create a new builder.
227
228 The builder will be set to manual. An admin needs to verify its
229 configuration and set it to automatic before jobs will be
230 dispatched.
231 """
232
233
234class IBuilderSet(IBuilderSetAdmin):
214 """Collections of builders.235 """Collections of builders.
215236
216 IBuilderSet provides access to all Builders in the system,237 IBuilderSet provides access to all Builders in the system,
@@ -219,7 +240,6 @@
219 methods that affect a single Builder should be on IBuilder.240 methods that affect a single Builder should be on IBuilder.
220 """241 """
221 export_as_webservice_collection(IBuilder)242 export_as_webservice_collection(IBuilder)
222
223 title = Attribute('Title')243 title = Attribute('Title')
224244
225 def __iter__():245 def __iter__():
@@ -235,18 +255,6 @@
235 def getByName(name):255 def getByName(name):
236 """Retrieve a builder by name"""256 """Retrieve a builder by name"""
237257
238 def new(processors, url, name, title, owner, active=True,
239 virtualized=False, vm_host=None):
240 """Create a new Builder entry.
241
242 Additionally to the given arguments, builder are created with
243 'builderok' and 'manual' set to True.
244
245 It means that, once created, they will be presented as 'functional'
246 in the UI but will not receive any job until an administrator move
247 it to the automatic mode.
248 """
249
250 def count():258 def count():
251 """Return the number of builders in the system."""259 """Return the number of builders in the system."""
252260
253261
=== modified file 'lib/lp/buildmaster/tests/test_webservice.py'
--- lib/lp/buildmaster/tests/test_webservice.py 2013-11-28 08:51:32 +0000
+++ lib/lp/buildmaster/tests/test_webservice.py 2014-04-23 11:07:46 +0000
@@ -5,13 +5,21 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8from zope.component import getUtility
9
10from lp.registry.interfaces.person import IPersonSet
11from lp.services.webapp.interfaces import OAuthPermission
8from lp.testing import (12from lp.testing import (
13 admin_logged_in,
9 api_url,14 api_url,
10 logout,15 logout,
11 TestCaseWithFactory,16 TestCaseWithFactory,
12 )17 )
13from lp.testing.layers import DatabaseFunctionalLayer18from lp.testing.layers import DatabaseFunctionalLayer
14from lp.testing.pages import LaunchpadWebServiceCaller19from lp.testing.pages import (
20 LaunchpadWebServiceCaller,
21 webservice_for_person,
22 )
1523
1624
17class TestBuildersCollection(TestCaseWithFactory):25class TestBuildersCollection(TestCaseWithFactory):
@@ -49,6 +57,27 @@
49 ['quantum_builder1', 'quantum_builder2'],57 ['quantum_builder1', 'quantum_builder2'],
50 sorted(builder['name'] for builder in results['entries']))58 sorted(builder['name'] for builder in results['entries']))
5159
60 def test_new(self):
61 person = self.factory.makePerson()
62 badmins = getUtility(IPersonSet).getByName('launchpad-buildd-admins')
63 webservice = webservice_for_person(
64 person, permission=OAuthPermission.WRITE_PRIVATE)
65 args = dict(
66 name='foo', processors=['/+processors/386'], title='foobar',
67 url='http://foo.buildd:8221/', virtualized=False,
68 api_version='devel')
69
70 response = webservice.named_post('/builders', 'new', **args)
71 self.assertEqual(401, response.status)
72
73 with admin_logged_in():
74 badmins.addMember(person, badmins)
75 response = webservice.named_post('/builders', 'new', **args)
76 self.assertEqual(201, response.status)
77
78 self.assertEqual(
79 'foobar', webservice.get('/builders/foo').jsonBody()['title'])
80
5281
53class TestBuilderEntry(TestCaseWithFactory):82class TestBuilderEntry(TestCaseWithFactory):
54 layer = DatabaseFunctionalLayer83 layer = DatabaseFunctionalLayer
5584
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2014-02-24 07:19:52 +0000
+++ lib/lp/testing/factory.py 2014-04-23 11:07:46 +0000
@@ -2760,9 +2760,10 @@
2760 if owner is None:2760 if owner is None:
2761 owner = self.makePerson()2761 owner = self.makePerson()
27622762
2763 return getUtility(IBuilderSet).new(2763 with admin_logged_in():
2764 processors, url, name, title, owner, active, virtualized, vm_host,2764 return getUtility(IBuilderSet).new(
2765 manual=manual)2765 processors, url, name, title, owner, active,
2766 virtualized, vm_host, manual=manual)
27662767
2767 def makeRecipeText(self, *branches):2768 def makeRecipeText(self, *branches):
2768 if len(branches) == 0:2769 if len(branches) == 0: