Merge lp:~julian-edwards/maas/nodegroup-on-bootimage-schema-part2 into lp:maas/trunk

Proposed by Julian Edwards on 2012-10-25
Status: Merged
Merged at revision: 1297
Proposed branch: lp:~julian-edwards/maas/nodegroup-on-bootimage-schema-part2
Merge into: lp:maas/trunk
Prerequisite: lp:~julian-edwards/maas/nodegroup-on-bootimage-schema
Diff against target: 356 lines (+85/-52)
11 files modified
src/maasserver/api.py (+4/-1)
src/maasserver/models/bootimage.py (+15/-10)
src/maasserver/preseed.py (+1/-1)
src/maasserver/testing/factory.py (+4/-1)
src/maasserver/tests/test_api.py (+27/-19)
src/maasserver/tests/test_bootimage.py (+20/-9)
src/maasserver/tests/test_preseed.py (+2/-2)
src/maasserver/tests/test_start_up.py (+1/-1)
src/provisioningserver/boot_images.py (+2/-1)
src/provisioningserver/testing/boot_images.py (+2/-4)
src/provisioningserver/tests/test_boot_images.py (+7/-3)
To merge this branch: bzr merge lp:~julian-edwards/maas/nodegroup-on-bootimage-schema-part2
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve on 2012-10-25
Gavin Panella (community) 2012-10-25 Approve on 2012-10-25
Review via email: mp+131331@code.launchpad.net

Commit message

Enable handling of NodeGroup as a FK on BootImage. All boot images must now be associated with a node group.

Description of the change

Enable handling of NodeGroup as a FK on BootImage. All boot images must now be associated with a node group.

To post a comment you must log in.
Gavin Panella (allenap) :
review: Approve
Julian Edwards (julian-edwards) wrote :

Taint bad.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api.py'
2--- src/maasserver/api.py 2012-10-19 13:55:51 +0000
3+++ src/maasserver/api.py 2012-10-25 07:51:20 +0000
4@@ -1861,11 +1861,14 @@
5 `purpose`, all as in the code that determines TFTP paths for
6 these images.
7 """
8- check_nodegroup_access(request, NodeGroup.objects.ensure_master())
9+ nodegroup_uuid = get_mandatory_param(request.data, "nodegroup")
10+ nodegroup = get_object_or_404(NodeGroup, uuid=nodegroup_uuid)
11+ check_nodegroup_access(request, nodegroup)
12 images = json.loads(get_mandatory_param(request.data, 'images'))
13
14 for image in images:
15 BootImage.objects.register_image(
16+ nodegroup=nodegroup,
17 architecture=image['architecture'],
18 subarchitecture=image.get('subarchitecture', 'generic'),
19 release=image['release'],
20
21=== modified file 'src/maasserver/models/bootimage.py'
22--- src/maasserver/models/bootimage.py 2012-10-25 07:51:20 +0000
23+++ src/maasserver/models/bootimage.py 2012-10-25 07:51:20 +0000
24@@ -31,25 +31,30 @@
25 Don't import or instantiate this directly; access as `BootImage.objects`.
26 """
27
28- def get_by_natural_key(self, architecture, subarchitecture, release,
29- purpose):
30+ def get_by_natural_key(self, nodegroup, architecture, subarchitecture,
31+ release, purpose):
32 """Look up a specific image."""
33 return self.get(
34- architecture=architecture, subarchitecture=subarchitecture,
35- release=release, purpose=purpose)
36+ nodegroup=nodegroup, architecture=architecture,
37+ subarchitecture=subarchitecture, release=release,
38+ purpose=purpose)
39
40- def register_image(self, architecture, subarchitecture, release, purpose):
41+ def register_image(self, nodegroup, architecture, subarchitecture,
42+ release, purpose):
43 """Register an image if it wasn't already registered."""
44 self.get_or_create(
45- architecture=architecture, subarchitecture=subarchitecture,
46- release=release, purpose=purpose)
47+ nodegroup=nodegroup, architecture=architecture,
48+ subarchitecture=subarchitecture, release=release,
49+ purpose=purpose)
50
51- def have_image(self, architecture, subarchitecture, release, purpose):
52+ def have_image(self, nodegroup, architecture, subarchitecture, release,
53+ purpose):
54 """Is an image for the given kind of boot available?"""
55 try:
56 self.get_by_natural_key(
57- architecture=architecture, subarchitecture=subarchitecture,
58- release=release, purpose=purpose)
59+ nodegroup=nodegroup, architecture=architecture,
60+ subarchitecture=subarchitecture, release=release,
61+ purpose=purpose)
62 return True
63 except BootImage.DoesNotExist:
64 return False
65
66=== modified file 'src/maasserver/preseed.py'
67--- src/maasserver/preseed.py 2012-10-02 21:07:00 +0000
68+++ src/maasserver/preseed.py 2012-10-25 07:51:20 +0000
69@@ -242,7 +242,7 @@
70 """Whether or not the SquashFS image can be used during installation."""
71 arch, subarch = node.architecture.split("/")
72 return BootImage.objects.have_image(
73- arch, subarch, node.get_distro_series(), "filesystem")
74+ node.nodegroup, arch, subarch, node.get_distro_series(), "filesystem")
75
76
77 def render_preseed(node, prefix, release=''):
78
79=== modified file 'src/maasserver/testing/factory.py'
80--- src/maasserver/testing/factory.py 2012-10-02 22:28:07 +0000
81+++ src/maasserver/testing/factory.py 2012-10-25 07:51:20 +0000
82@@ -325,7 +325,7 @@
83 '%s="%s"' % (key, value) for key, value in items.items()])
84
85 def make_boot_image(self, architecture=None, subarchitecture=None,
86- release=None, purpose=None):
87+ release=None, purpose=None, nodegroup=None):
88 if architecture is None:
89 architecture = self.make_name('architecture')
90 if subarchitecture is None:
91@@ -334,7 +334,10 @@
92 release = self.make_name('release')
93 if purpose is None:
94 purpose = self.make_name('purpose')
95+ if nodegroup is None:
96+ nodegroup = self.make_node_group()
97 return BootImage.objects.create(
98+ nodegroup=nodegroup,
99 architecture=architecture,
100 subarchitecture=subarchitecture,
101 release=release,
102
103=== modified file 'src/maasserver/tests/test_api.py'
104--- src/maasserver/tests/test_api.py 2012-10-19 13:33:31 +0000
105+++ src/maasserver/tests/test_api.py 2012-10-25 07:51:20 +0000
106@@ -4026,48 +4026,55 @@
107 ('celery', FixtureResource(CeleryFixture())),
108 )
109
110- def report_images(self, images, client=None):
111+ def report_images(self, nodegroup, images, client=None):
112 if client is None:
113 client = self.client
114 return client.post(
115- reverse('boot_images_handler'),
116- {'op': 'report_boot_images', 'images': json.dumps(images)})
117+ reverse('boot_images_handler'), {
118+ 'images': json.dumps(images),
119+ 'nodegroup': nodegroup.uuid,
120+ 'op': 'report_boot_images',
121+ })
122
123 def test_report_boot_images_does_not_work_for_normal_user(self):
124- NodeGroup.objects.ensure_master()
125+ nodegroup = NodeGroup.objects.ensure_master()
126 log_in_as_normal_user(self.client)
127- response = self.report_images([])
128- self.assertEqual(httplib.FORBIDDEN, response.status_code)
129+ response = self.report_images(nodegroup, [])
130+ self.assertEqual(
131+ httplib.FORBIDDEN, response.status_code, response.content)
132
133 def test_report_boot_images_works_for_master_worker(self):
134- client = make_worker_client(NodeGroup.objects.ensure_master())
135- response = self.report_images([], client=client)
136+ nodegroup = NodeGroup.objects.ensure_master()
137+ client = make_worker_client(nodegroup)
138+ response = self.report_images(nodegroup, [], client=client)
139 self.assertEqual(httplib.OK, response.status_code)
140
141 def test_report_boot_images_stores_images(self):
142+ nodegroup = NodeGroup.objects.ensure_master()
143 image = make_boot_image_params()
144- client = make_worker_client(NodeGroup.objects.ensure_master())
145- response = self.report_images([image], client=client)
146+ client = make_worker_client(nodegroup)
147+ response = self.report_images(nodegroup, [image], client=client)
148 self.assertEqual(
149 (httplib.OK, "OK"),
150 (response.status_code, response.content))
151 self.assertTrue(
152- BootImage.objects.have_image(**image))
153+ BootImage.objects.have_image(nodegroup=nodegroup, **image))
154
155 def test_report_boot_images_ignores_unknown_image_properties(self):
156+ nodegroup = NodeGroup.objects.ensure_master()
157 image = make_boot_image_params()
158 image['nonesuch'] = factory.make_name('nonesuch'),
159- client = make_worker_client(NodeGroup.objects.ensure_master())
160- response = self.report_images([image], client=client)
161+ client = make_worker_client(nodegroup)
162+ response = self.report_images(nodegroup, [image], client=client)
163 self.assertEqual(
164 (httplib.OK, "OK"),
165 (response.status_code, response.content))
166
167 def test_report_boot_images_warns_if_no_images_found(self):
168+ nodegroup = NodeGroup.objects.ensure_master()
169 recorder = self.patch(api, 'register_persistent_error')
170- client = make_worker_client(NodeGroup.objects.ensure_master())
171-
172- response = self.report_images([], client=client)
173+ client = make_worker_client(nodegroup)
174+ response = self.report_images(nodegroup, [], client=client)
175 self.assertEqual(
176 (httplib.OK, "OK"),
177 (response.status_code, response.content))
178@@ -4079,10 +4086,11 @@
179 def test_report_boot_images_removes_warning_if_images_found(self):
180 self.patch(api, 'register_persistent_error')
181 self.patch(api, 'discard_persistent_error')
182- client = make_worker_client(NodeGroup.objects.ensure_master())
183+ nodegroup = factory.make_node_group()
184+ image = make_boot_image_params()
185+ client = make_worker_client(nodegroup)
186
187- response = self.report_images(
188- [make_boot_image_params()], client=client)
189+ response = self.report_images(nodegroup, [image], client=client)
190 self.assertEqual(
191 (httplib.OK, "OK"),
192 (response.status_code, response.content))
193
194=== modified file 'src/maasserver/tests/test_bootimage.py'
195--- src/maasserver/tests/test_bootimage.py 2012-09-14 14:16:01 +0000
196+++ src/maasserver/tests/test_bootimage.py 2012-10-25 07:51:20 +0000
197@@ -12,7 +12,10 @@
198 __metaclass__ = type
199 __all__ = []
200
201-from maasserver.models import BootImage
202+from maasserver.models import (
203+ BootImage,
204+ NodeGroup,
205+ )
206 from maasserver.testing.factory import factory
207 from maasserver.testing.testcase import TestCase
208 from provisioningserver.testing.boot_images import make_boot_image_params
209@@ -20,22 +23,30 @@
210
211 class TestBootImageManager(TestCase):
212
213+ def setUp(self):
214+ super(TestBootImageManager, self).setUp()
215+ self.nodegroup = NodeGroup.objects.ensure_master()
216+
217 def test_have_image_returns_False_if_image_not_available(self):
218 self.assertFalse(
219- BootImage.objects.have_image(**make_boot_image_params()))
220+ BootImage.objects.have_image(
221+ self.nodegroup, **make_boot_image_params()))
222
223 def test_have_image_returns_True_if_image_available(self):
224 params = make_boot_image_params()
225- factory.make_boot_image(**params)
226- self.assertTrue(BootImage.objects.have_image(**params))
227+ factory.make_boot_image(nodegroup=self.nodegroup, **params)
228+ self.assertTrue(
229+ BootImage.objects.have_image(self.nodegroup, **params))
230
231 def test_register_image_registers_new_image(self):
232 params = make_boot_image_params()
233- BootImage.objects.register_image(**params)
234- self.assertTrue(BootImage.objects.have_image(**params))
235+ BootImage.objects.register_image(self.nodegroup, **params)
236+ self.assertTrue(
237+ BootImage.objects.have_image(self.nodegroup, **params))
238
239 def test_register_image_leaves_existing_image_intact(self):
240 params = make_boot_image_params()
241- factory.make_boot_image(**params)
242- BootImage.objects.register_image(**params)
243- self.assertTrue(BootImage.objects.have_image(**params))
244+ factory.make_boot_image(nodegroup=self.nodegroup, **params)
245+ BootImage.objects.register_image(self.nodegroup, **params)
246+ self.assertTrue(
247+ BootImage.objects.have_image(self.nodegroup, **params))
248
249=== modified file 'src/maasserver/tests/test_preseed.py'
250--- src/maasserver/tests/test_preseed.py 2012-10-05 04:21:12 +0000
251+++ src/maasserver/tests/test_preseed.py 2012-10-25 07:51:20 +0000
252@@ -330,10 +330,10 @@
253 )
254
255 def test_squashfs_available(self):
256- BootImage.objects.register_image(
257- self.arch, self.subarch, self.series, self.purpose)
258 node = factory.make_node(
259 architecture="i386/generic", distro_series="quantal")
260+ BootImage.objects.register_image(
261+ node.nodegroup, self.arch, self.subarch, self.series, self.purpose)
262 self.assertEqual(self.present, is_squashfs_image_present(node))
263
264
265
266=== modified file 'src/maasserver/tests/test_start_up.py'
267--- src/maasserver/tests/test_start_up.py 2012-09-28 18:42:16 +0000
268+++ src/maasserver/tests/test_start_up.py 2012-10-25 07:51:20 +0000
269@@ -32,9 +32,9 @@
270 NodeGroup,
271 )
272 from maasserver.testing.factory import factory
273+from maasserver.testing.testcase import TestCase
274 from maastesting.celery import CeleryFixture
275 from maastesting.fakemethod import FakeMethod
276-from maastesting.testcase import TestCase
277 from mock import Mock
278 from provisioningserver import tasks
279 from testresources import FixtureResource
280
281=== modified file 'src/provisioningserver/boot_images.py'
282--- src/provisioningserver/boot_images.py 2012-10-19 15:08:52 +0000
283+++ src/provisioningserver/boot_images.py 2012-10-25 07:51:20 +0000
284@@ -32,6 +32,7 @@
285 )
286 from provisioningserver.config import Config
287 from provisioningserver.pxe import tftppath
288+from provisioningserver.start_cluster_controller import get_cluster_uuid
289
290
291 task_logger = get_task_logger(name=__name__)
292@@ -56,7 +57,7 @@
293 """Submit images to server."""
294 MAASClient(MAASOAuth(*api_credentials), MAASDispatcher(), maas_url).post(
295 'api/1.0/boot-images/', 'report_boot_images',
296- images=json.dumps(images))
297+ nodegroup=get_cluster_uuid(), images=json.dumps(images))
298
299
300 def report_to_server():
301
302=== modified file 'src/provisioningserver/testing/boot_images.py'
303--- src/provisioningserver/testing/boot_images.py 2012-09-14 14:16:01 +0000
304+++ src/provisioningserver/testing/boot_images.py 2012-10-25 07:51:20 +0000
305@@ -17,7 +17,7 @@
306 from maastesting.factory import factory
307
308
309-def make_boot_image_params(**kwargs):
310+def make_boot_image_params():
311 """Create an arbitrary dict of boot-image parameters.
312
313 These are the parameters that together describe a kind of boot that we
314@@ -25,10 +25,8 @@
315 Ubuntu release, and boot purpose. See the `tftppath` module for how
316 these fit together.
317 """
318- fields = dict(
319+ return dict(
320 architecture=factory.make_name('architecture'),
321 subarchitecture=factory.make_name('subarchitecture'),
322 release=factory.make_name('release'),
323 purpose=factory.make_name('purpose'))
324- fields.update(kwargs)
325- return fields
326
327=== modified file 'src/provisioningserver/tests/test_boot_images.py'
328--- src/provisioningserver/tests/test_boot_images.py 2012-10-04 05:49:09 +0000
329+++ src/provisioningserver/tests/test_boot_images.py 2012-10-25 07:51:20 +0000
330@@ -15,7 +15,10 @@
331 import json
332
333 from apiclient.maas_client import MAASClient
334-from mock import Mock
335+from mock import (
336+ Mock,
337+ sentinel,
338+ )
339 from provisioningserver import boot_images
340 from provisioningserver.pxe import tftppath
341 from provisioningserver.testing.boot_images import make_boot_image_params
342@@ -34,11 +37,12 @@
343 self.set_api_credentials()
344 image = make_boot_image_params()
345 self.patch(tftppath, 'list_boot_images', Mock(return_value=[image]))
346+ get_cluster_uuid = self.patch(boot_images, "get_cluster_uuid")
347+ get_cluster_uuid.return_value = sentinel.uuid
348 self.patch(MAASClient, 'post')
349-
350 boot_images.report_to_server()
351-
352 args, kwargs = MAASClient.post.call_args
353+ self.assertIs(sentinel.uuid, kwargs["nodegroup"])
354 self.assertItemsEqual([image], json.loads(kwargs['images']))
355
356 def test_does_nothing_without_maas_url(self):