← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Julian Edwards has proposed merging lp:~julian-edwards/maas/nodegroup-on-bootimage-schema-part2 into lp:maas with lp:~julian-edwards/maas/nodegroup-on-bootimage-schema as a prerequisite.

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

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~julian-edwards/maas/nodegroup-on-bootimage-schema-part2/+merge/131331

Enable handling of NodeGroup as a FK on BootImage.  All boot images must now be associated with a node group.
-- 
https://code.launchpad.net/~julian-edwards/maas/nodegroup-on-bootimage-schema-part2/+merge/131331
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/maas/nodegroup-on-bootimage-schema-part2 into lp:maas.
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py	2012-10-19 13:55:51 +0000
+++ src/maasserver/api.py	2012-10-25 07:51:20 +0000
@@ -1861,11 +1861,14 @@
             `purpose`, all as in the code that determines TFTP paths for
             these images.
         """
-        check_nodegroup_access(request, NodeGroup.objects.ensure_master())
+        nodegroup_uuid = get_mandatory_param(request.data, "nodegroup")
+        nodegroup = get_object_or_404(NodeGroup, uuid=nodegroup_uuid)
+        check_nodegroup_access(request, nodegroup)
         images = json.loads(get_mandatory_param(request.data, 'images'))
 
         for image in images:
             BootImage.objects.register_image(
+                nodegroup=nodegroup,
                 architecture=image['architecture'],
                 subarchitecture=image.get('subarchitecture', 'generic'),
                 release=image['release'],

=== modified file 'src/maasserver/models/bootimage.py'
--- src/maasserver/models/bootimage.py	2012-10-25 07:51:20 +0000
+++ src/maasserver/models/bootimage.py	2012-10-25 07:51:20 +0000
@@ -31,25 +31,30 @@
     Don't import or instantiate this directly; access as `BootImage.objects`.
     """
 
-    def get_by_natural_key(self, architecture, subarchitecture, release,
-                           purpose):
+    def get_by_natural_key(self, nodegroup, architecture, subarchitecture,
+                           release, purpose):
         """Look up a specific image."""
         return self.get(
-            architecture=architecture, subarchitecture=subarchitecture,
-            release=release, purpose=purpose)
+            nodegroup=nodegroup, architecture=architecture,
+            subarchitecture=subarchitecture, release=release,
+            purpose=purpose)
 
-    def register_image(self, architecture, subarchitecture, release, purpose):
+    def register_image(self, nodegroup, architecture, subarchitecture,
+                       release, purpose):
         """Register an image if it wasn't already registered."""
         self.get_or_create(
-            architecture=architecture, subarchitecture=subarchitecture,
-            release=release, purpose=purpose)
+            nodegroup=nodegroup, architecture=architecture,
+            subarchitecture=subarchitecture, release=release,
+            purpose=purpose)
 
-    def have_image(self, architecture, subarchitecture, release, purpose):
+    def have_image(self, nodegroup, architecture, subarchitecture, release,
+                   purpose):
         """Is an image for the given kind of boot available?"""
         try:
             self.get_by_natural_key(
-                architecture=architecture, subarchitecture=subarchitecture,
-                release=release, purpose=purpose)
+                nodegroup=nodegroup, architecture=architecture,
+                subarchitecture=subarchitecture, release=release,
+                purpose=purpose)
             return True
         except BootImage.DoesNotExist:
             return False

=== modified file 'src/maasserver/preseed.py'
--- src/maasserver/preseed.py	2012-10-02 21:07:00 +0000
+++ src/maasserver/preseed.py	2012-10-25 07:51:20 +0000
@@ -242,7 +242,7 @@
     """Whether or not the SquashFS image can be used during installation."""
     arch, subarch = node.architecture.split("/")
     return BootImage.objects.have_image(
-        arch, subarch, node.get_distro_series(), "filesystem")
+        node.nodegroup, arch, subarch, node.get_distro_series(), "filesystem")
 
 
 def render_preseed(node, prefix, release=''):

=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py	2012-10-02 22:28:07 +0000
+++ src/maasserver/testing/factory.py	2012-10-25 07:51:20 +0000
@@ -325,7 +325,7 @@
             '%s="%s"' % (key, value) for key, value in items.items()])
 
     def make_boot_image(self, architecture=None, subarchitecture=None,
-                        release=None, purpose=None):
+                        release=None, purpose=None, nodegroup=None):
         if architecture is None:
             architecture = self.make_name('architecture')
         if subarchitecture is None:
@@ -334,7 +334,10 @@
             release = self.make_name('release')
         if purpose is None:
             purpose = self.make_name('purpose')
+        if nodegroup is None:
+            nodegroup = self.make_node_group()
         return BootImage.objects.create(
+            nodegroup=nodegroup,
             architecture=architecture,
             subarchitecture=subarchitecture,
             release=release,

=== modified file 'src/maasserver/tests/test_api.py'
--- src/maasserver/tests/test_api.py	2012-10-19 13:33:31 +0000
+++ src/maasserver/tests/test_api.py	2012-10-25 07:51:20 +0000
@@ -4026,48 +4026,55 @@
         ('celery', FixtureResource(CeleryFixture())),
         )
 
-    def report_images(self, images, client=None):
+    def report_images(self, nodegroup, images, client=None):
         if client is None:
             client = self.client
         return client.post(
-            reverse('boot_images_handler'),
-            {'op': 'report_boot_images', 'images': json.dumps(images)})
+            reverse('boot_images_handler'), {
+                'images': json.dumps(images),
+                'nodegroup': nodegroup.uuid,
+                'op': 'report_boot_images',
+                })
 
     def test_report_boot_images_does_not_work_for_normal_user(self):
-        NodeGroup.objects.ensure_master()
+        nodegroup = NodeGroup.objects.ensure_master()
         log_in_as_normal_user(self.client)
-        response = self.report_images([])
-        self.assertEqual(httplib.FORBIDDEN, response.status_code)
+        response = self.report_images(nodegroup, [])
+        self.assertEqual(
+            httplib.FORBIDDEN, response.status_code, response.content)
 
     def test_report_boot_images_works_for_master_worker(self):
-        client = make_worker_client(NodeGroup.objects.ensure_master())
-        response = self.report_images([], client=client)
+        nodegroup = NodeGroup.objects.ensure_master()
+        client = make_worker_client(nodegroup)
+        response = self.report_images(nodegroup, [], client=client)
         self.assertEqual(httplib.OK, response.status_code)
 
     def test_report_boot_images_stores_images(self):
+        nodegroup = NodeGroup.objects.ensure_master()
         image = make_boot_image_params()
-        client = make_worker_client(NodeGroup.objects.ensure_master())
-        response = self.report_images([image], client=client)
+        client = make_worker_client(nodegroup)
+        response = self.report_images(nodegroup, [image], client=client)
         self.assertEqual(
             (httplib.OK, "OK"),
             (response.status_code, response.content))
         self.assertTrue(
-            BootImage.objects.have_image(**image))
+            BootImage.objects.have_image(nodegroup=nodegroup, **image))
 
     def test_report_boot_images_ignores_unknown_image_properties(self):
+        nodegroup = NodeGroup.objects.ensure_master()
         image = make_boot_image_params()
         image['nonesuch'] = factory.make_name('nonesuch'),
-        client = make_worker_client(NodeGroup.objects.ensure_master())
-        response = self.report_images([image], client=client)
+        client = make_worker_client(nodegroup)
+        response = self.report_images(nodegroup, [image], client=client)
         self.assertEqual(
             (httplib.OK, "OK"),
             (response.status_code, response.content))
 
     def test_report_boot_images_warns_if_no_images_found(self):
+        nodegroup = NodeGroup.objects.ensure_master()
         recorder = self.patch(api, 'register_persistent_error')
-        client = make_worker_client(NodeGroup.objects.ensure_master())
-
-        response = self.report_images([], client=client)
+        client = make_worker_client(nodegroup)
+        response = self.report_images(nodegroup, [], client=client)
         self.assertEqual(
             (httplib.OK, "OK"),
             (response.status_code, response.content))
@@ -4079,10 +4086,11 @@
     def test_report_boot_images_removes_warning_if_images_found(self):
         self.patch(api, 'register_persistent_error')
         self.patch(api, 'discard_persistent_error')
-        client = make_worker_client(NodeGroup.objects.ensure_master())
+        nodegroup = factory.make_node_group()
+        image = make_boot_image_params()
+        client = make_worker_client(nodegroup)
 
-        response = self.report_images(
-            [make_boot_image_params()], client=client)
+        response = self.report_images(nodegroup, [image], client=client)
         self.assertEqual(
             (httplib.OK, "OK"),
             (response.status_code, response.content))

=== modified file 'src/maasserver/tests/test_bootimage.py'
--- src/maasserver/tests/test_bootimage.py	2012-09-14 14:16:01 +0000
+++ src/maasserver/tests/test_bootimage.py	2012-10-25 07:51:20 +0000
@@ -12,7 +12,10 @@
 __metaclass__ = type
 __all__ = []
 
-from maasserver.models import BootImage
+from maasserver.models import (
+    BootImage,
+    NodeGroup,
+    )
 from maasserver.testing.factory import factory
 from maasserver.testing.testcase import TestCase
 from provisioningserver.testing.boot_images import make_boot_image_params
@@ -20,22 +23,30 @@
 
 class TestBootImageManager(TestCase):
 
+    def setUp(self):
+        super(TestBootImageManager, self).setUp()
+        self.nodegroup = NodeGroup.objects.ensure_master()
+
     def test_have_image_returns_False_if_image_not_available(self):
         self.assertFalse(
-            BootImage.objects.have_image(**make_boot_image_params()))
+            BootImage.objects.have_image(
+                self.nodegroup, **make_boot_image_params()))
 
     def test_have_image_returns_True_if_image_available(self):
         params = make_boot_image_params()
-        factory.make_boot_image(**params)
-        self.assertTrue(BootImage.objects.have_image(**params))
+        factory.make_boot_image(nodegroup=self.nodegroup, **params)
+        self.assertTrue(
+            BootImage.objects.have_image(self.nodegroup, **params))
 
     def test_register_image_registers_new_image(self):
         params = make_boot_image_params()
-        BootImage.objects.register_image(**params)
-        self.assertTrue(BootImage.objects.have_image(**params))
+        BootImage.objects.register_image(self.nodegroup, **params)
+        self.assertTrue(
+            BootImage.objects.have_image(self.nodegroup, **params))
 
     def test_register_image_leaves_existing_image_intact(self):
         params = make_boot_image_params()
-        factory.make_boot_image(**params)
-        BootImage.objects.register_image(**params)
-        self.assertTrue(BootImage.objects.have_image(**params))
+        factory.make_boot_image(nodegroup=self.nodegroup, **params)
+        BootImage.objects.register_image(self.nodegroup, **params)
+        self.assertTrue(
+            BootImage.objects.have_image(self.nodegroup, **params))

=== modified file 'src/maasserver/tests/test_preseed.py'
--- src/maasserver/tests/test_preseed.py	2012-10-05 04:21:12 +0000
+++ src/maasserver/tests/test_preseed.py	2012-10-25 07:51:20 +0000
@@ -330,10 +330,10 @@
         )
 
     def test_squashfs_available(self):
-        BootImage.objects.register_image(
-            self.arch, self.subarch, self.series, self.purpose)
         node = factory.make_node(
             architecture="i386/generic", distro_series="quantal")
+        BootImage.objects.register_image(
+            node.nodegroup, self.arch, self.subarch, self.series, self.purpose)
         self.assertEqual(self.present, is_squashfs_image_present(node))
 
 

=== modified file 'src/maasserver/tests/test_start_up.py'
--- src/maasserver/tests/test_start_up.py	2012-09-28 18:42:16 +0000
+++ src/maasserver/tests/test_start_up.py	2012-10-25 07:51:20 +0000
@@ -32,9 +32,9 @@
     NodeGroup,
     )
 from maasserver.testing.factory import factory
+from maasserver.testing.testcase import TestCase
 from maastesting.celery import CeleryFixture
 from maastesting.fakemethod import FakeMethod
-from maastesting.testcase import TestCase
 from mock import Mock
 from provisioningserver import tasks
 from testresources import FixtureResource

=== modified file 'src/provisioningserver/boot_images.py'
--- src/provisioningserver/boot_images.py	2012-10-19 15:08:52 +0000
+++ src/provisioningserver/boot_images.py	2012-10-25 07:51:20 +0000
@@ -32,6 +32,7 @@
     )
 from provisioningserver.config import Config
 from provisioningserver.pxe import tftppath
+from provisioningserver.start_cluster_controller import get_cluster_uuid
 
 
 task_logger = get_task_logger(name=__name__)
@@ -56,7 +57,7 @@
     """Submit images to server."""
     MAASClient(MAASOAuth(*api_credentials), MAASDispatcher(), maas_url).post(
         'api/1.0/boot-images/', 'report_boot_images',
-        images=json.dumps(images))
+        nodegroup=get_cluster_uuid(), images=json.dumps(images))
 
 
 def report_to_server():

=== modified file 'src/provisioningserver/testing/boot_images.py'
--- src/provisioningserver/testing/boot_images.py	2012-09-14 14:16:01 +0000
+++ src/provisioningserver/testing/boot_images.py	2012-10-25 07:51:20 +0000
@@ -17,7 +17,7 @@
 from maastesting.factory import factory
 
 
-def make_boot_image_params(**kwargs):
+def make_boot_image_params():
     """Create an arbitrary dict of boot-image parameters.
 
     These are the parameters that together describe a kind of boot that we
@@ -25,10 +25,8 @@
     Ubuntu release, and boot purpose.  See the `tftppath` module for how
     these fit together.
     """
-    fields = dict(
+    return dict(
         architecture=factory.make_name('architecture'),
         subarchitecture=factory.make_name('subarchitecture'),
         release=factory.make_name('release'),
         purpose=factory.make_name('purpose'))
-    fields.update(kwargs)
-    return fields

=== modified file 'src/provisioningserver/tests/test_boot_images.py'
--- src/provisioningserver/tests/test_boot_images.py	2012-10-04 05:49:09 +0000
+++ src/provisioningserver/tests/test_boot_images.py	2012-10-25 07:51:20 +0000
@@ -15,7 +15,10 @@
 import json
 
 from apiclient.maas_client import MAASClient
-from mock import Mock
+from mock import (
+    Mock,
+    sentinel,
+    )
 from provisioningserver import boot_images
 from provisioningserver.pxe import tftppath
 from provisioningserver.testing.boot_images import make_boot_image_params
@@ -34,11 +37,12 @@
         self.set_api_credentials()
         image = make_boot_image_params()
         self.patch(tftppath, 'list_boot_images', Mock(return_value=[image]))
+        get_cluster_uuid = self.patch(boot_images, "get_cluster_uuid")
+        get_cluster_uuid.return_value = sentinel.uuid
         self.patch(MAASClient, 'post')
-
         boot_images.report_to_server()
-
         args, kwargs = MAASClient.post.call_args
+        self.assertIs(sentinel.uuid, kwargs["nodegroup"])
         self.assertItemsEqual([image], json.loads(kwargs['images']))
 
     def test_does_nothing_without_maas_url(self):