launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #13710
[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):