Merge lp:~blake-rouse/maas/fix-1439359 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 3787
Proposed branch: lp:~blake-rouse/maas/fix-1439359
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 197 lines (+126/-4)
2 files modified
src/maasserver/start_up.py (+67/-2)
src/maasserver/tests/test_start_up.py (+59/-2)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1439359
Reviewer Review Type Date Requested Status
Andres Rodriguez (community) Approve
Review via email: mp+255206@code.launchpad.net

Commit message

Set the correct boot source selections and start importing of boot resources if the cluster already has boot images.

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :
Download full text (3.3 KiB)

Should we consider that we need to import the same arches / releases as
those that have already been imported previously? I think we should.
On Apr 3, 2015 15:06, "Blake Rouse" <email address hidden> wrote:

> Blake Rouse has proposed merging lp:~blake-rouse/maas/fix-1439359 into
> lp:maas.
>
> Commit message:
> Automatically start importing of boot resources if the cluster already has
> boot images.
>
> Requested reviews:
> MAAS Maintainers (maas-maintainers)
> Related bugs:
> Bug #1439359 in MAAS: "When upgrading to MAAS 1.7 from MAAS 1.5, MAAS
> should trigger the image import automatically."
> https://bugs.launchpad.net/maas/+bug/1439359
>
> For more details, see:
> https://code.launchpad.net/~blake-rouse/maas/fix-1439359/+merge/255206
> --
> You are subscribed to branch lp:maas.
>
> === modified file 'src/maasserver/bootresources.py'
> --- src/maasserver/bootresources.py 2015-03-25 15:33:23 +0000
> +++ src/maasserver/bootresources.py 2015-04-03 19:06:06 +0000
> @@ -1027,6 +1027,13 @@
> images_link = absolute_url_reverse('images')
> boot_images_locally = list_boot_images()
> if len(boot_images_locally) > 0:
> + # Start the import process for the user, since the cluster
> + # already has images. Even though the cluster is usable
> the
> + # region will not be usable until it has boot images as
> well.
> + import_resources()
> +
> + # Show the warning as well. This will do away once the
> images
> + # have been imported.
> warning = (
> "Your cluster currently has boot images, but your
> region "
> "does not. Nodes will not be able to provision until
> you "
>
> === modified file 'src/maasserver/tests/test_bootresources.py'
> --- src/maasserver/tests/test_bootresources.py 2015-03-25 15:33:23 +0000
> +++ src/maasserver/tests/test_bootresources.py 2015-04-03 19:06:06 +0000
> @@ -1268,6 +1268,7 @@
> utils_module.settings, 'DEFAULT_MAAS_URL', 'http://%s' %
> abs_path)
> list_boot_images = self.patch(bootresources, "list_boot_images")
> list_boot_images.return_value = [make_rpc_boot_image()]
> + self.patch(bootresources, "import_resources")
>
> service = bootresources.ImportResourcesProgressService()
> service.check_boot_images()
> @@ -1284,6 +1285,18 @@
> normalise_whitespace(error_expected % images_link),
> error_observed)
>
> + def
> test__starts_import_if_boot_images_exists_on_cluster_not_region(self):
> + abs_path = "/%s/%s/" % (factory.make_string(),
> factory.make_string())
> + self.patch(
> + utils_module.settings, 'DEFAULT_MAAS_URL', 'http://%s' %
> abs_path)
> + list_boot_images = self.patch(bootresources, "list_boot_images")
> + list_boot_images.return_value = [make_rpc_boot_image()]
> + import_resources = self.patch(bootresources, "import_resources")
> +
> + service = bootresources.ImportResourcesProgressService()
> + service.check_boot_images()
> + self.assertThat(import_resourc...

Read more...

Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm!

review: Approve
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm! I only have one comment, not a blocker though.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/start_up.py'
2--- src/maasserver/start_up.py 2015-03-25 15:33:23 +0000
3+++ src/maasserver/start_up.py 2015-04-07 17:43:48 +0000
4@@ -25,10 +25,18 @@
5 locks,
6 security,
7 )
8-from maasserver.bootresources import ensure_boot_source_definition
9+from maasserver.bootresources import (
10+ ensure_boot_source_definition,
11+ import_resources,
12+)
13 from maasserver.dns.config import dns_update_all_zones
14 from maasserver.fields import register_mac_type
15-from maasserver.models import NodeGroup
16+from maasserver.models import (
17+ BootResource,
18+ BootSource,
19+ BootSourceSelection,
20+ NodeGroup,
21+)
22 from maasserver.triggers import register_all_triggers
23 from maasserver.utils import synchronised
24 from maasserver.utils.orm import (
25@@ -36,6 +44,7 @@
26 transactional,
27 )
28 from provisioningserver.logger import get_maas_logger
29+from provisioningserver.rpc.boot_images import list_boot_images
30 from provisioningserver.upgrade_cluster import create_gnupg_home
31
32
33@@ -90,6 +99,59 @@
34 break
35
36
37+def start_import_on_upgrade():
38+ """Starts importing `BootResource`s on upgrade from MAAS where the boot
39+ images where only stored on the clusters."""
40+ # Do nothing, because `BootResource`s already exist.
41+ if BootResource.objects.exists():
42+ return
43+
44+ # Do nothing if the cluster on the machine does not have
45+ # boot images present.
46+ boot_images = list_boot_images()
47+ if len(boot_images) == 0:
48+ return
49+
50+ # Build the selections that need to be set based on the images
51+ # that live on the cluster.
52+ osystems = dict()
53+ for image in boot_images:
54+ osystem = image["osystem"]
55+ if osystem not in osystems:
56+ osystems[osystem] = {
57+ "arches": set(),
58+ "releases": set(),
59+ "labels": set(),
60+ }
61+ osystems[osystem]["arches"].add(
62+ image["architecture"])
63+ osystems[osystem]["releases"].add(
64+ image["release"])
65+ osystems[osystem]["labels"].add(
66+ image["label"])
67+
68+ # We have no way to truly know which boot source this came
69+ # from, but since this should only occur on upgrade we
70+ # take the first source, which will be the default source and
71+ # apply the selection to that source.
72+ boot_source = BootSource.objects.first()
73+
74+ # Clear all current selections and create the new selections
75+ # based on the information retrieved from list_boot_images.
76+ boot_source.bootsourceselection_set.all().delete()
77+ for osystem, options in osystems.items():
78+ for release in options["releases"]:
79+ BootSourceSelection.objects.create(
80+ boot_source=boot_source, os=osystem,
81+ release=release, arches=list(options["arches"]),
82+ subarches=["*"], labels=list(options["labels"]))
83+
84+ # Start the import process for the user, since the cluster
85+ # already has images. Even though the cluster is usable the
86+ # region will not be usable until it has boot images as well.
87+ import_resources()
88+
89+
90 @transactional
91 @synchronised(locks.startup)
92 def inner_start_up():
93@@ -109,6 +171,9 @@
94 # If there are no boot-source definitions yet, create defaults.
95 ensure_boot_source_definition()
96
97+ # Start import on upgrade if needed.
98+ start_import_on_upgrade()
99+
100 # Register all of the triggers.
101 register_all_triggers()
102
103
104=== modified file 'src/maasserver/tests/test_start_up.py'
105--- src/maasserver/tests/test_start_up.py 2015-03-25 15:33:23 +0000
106+++ src/maasserver/tests/test_start_up.py 2015-04-07 17:43:48 +0000
107@@ -19,20 +19,27 @@
108 locks,
109 start_up,
110 )
111+from maasserver.bootresources import ensure_boot_source_definition
112+from maasserver.clusterrpc.testing.boot_images import make_rpc_boot_image
113 from maasserver.models import (
114 BootSource,
115+ BootSourceSelection,
116 NodeGroup,
117 )
118 from maasserver.testing.eventloop import RegionEventLoopFixture
119+from maasserver.testing.factory import factory
120 from maasserver.testing.testcase import MAASServerTestCase
121-from maastesting.factory import factory
122 from maastesting.fakemethod import FakeMethod
123 from maastesting.matchers import (
124 MockCalledOnceWith,
125 MockCallsMatch,
126+ MockNotCalled,
127 )
128 from mock import call
129-from testtools.matchers import HasLength
130+from testtools.matchers import (
131+ Equals,
132+ HasLength,
133+)
134
135
136 class LockChecker:
137@@ -90,6 +97,51 @@
138 self.expectThat(sleep, MockCalledOnceWith(10.0))
139
140
141+class TestStartImportOnUpgrade(MAASServerTestCase):
142+ """Tests for the `start_import_on_upgrade` function."""
143+
144+ def setUp(self):
145+ super(TestStartImportOnUpgrade, self).setUp()
146+ ensure_boot_source_definition()
147+ self.mock_import_resources = self.patch(start_up, 'import_resources')
148+
149+ def test__does_nothing_if_boot_resources_exist(self):
150+ mock_list_boot_images = self.patch(start_up, 'list_boot_images')
151+ factory.make_BootResource()
152+ start_up.start_import_on_upgrade()
153+ self.assertThat(mock_list_boot_images, MockNotCalled())
154+
155+ def test__does_nothing_if_list_boot_images_is_empty(self):
156+ self.patch(start_up, 'list_boot_images').return_value = []
157+ start_up.start_import_on_upgrade()
158+ self.assertThat(self.mock_import_resources, MockNotCalled())
159+
160+ def test__calls_import_resources(self):
161+ self.patch(start_up, 'list_boot_images').return_value = [
162+ make_rpc_boot_image(),
163+ ]
164+ start_up.start_import_on_upgrade()
165+ self.assertThat(self.mock_import_resources, MockCalledOnceWith())
166+
167+ def test__sets_source_selections_based_on_boot_images(self):
168+ boot_images = [
169+ make_rpc_boot_image()
170+ for _ in range(3)
171+ ]
172+ self.patch(start_up, 'list_boot_images').return_value = boot_images
173+ start_up.start_import_on_upgrade()
174+
175+ boot_source = BootSource.objects.first()
176+ for image in boot_images:
177+ selection = BootSourceSelection.objects.get(
178+ boot_source=boot_source, os=image["osystem"],
179+ release=image["release"])
180+ self.assertIsNotNone(selection)
181+ self.expectThat(selection.arches, Equals([image["architecture"]]))
182+ self.expectThat(selection.subarches, Equals(["*"]))
183+ self.expectThat(selection.labels, Equals([image["label"]]))
184+
185+
186 class TestInnerStartUp(MAASServerTestCase):
187
188 """Tests for the actual work done in `inner_start_up`."""
189@@ -127,3 +179,8 @@
190 self.assertItemsEqual([], BootSource.objects.all())
191 start_up.inner_start_up()
192 self.assertThat(BootSource.objects.all(), HasLength(1))
193+
194+ def test__calls_start_import_on_upgrade(self):
195+ mock_start_import = self.patch(start_up, 'start_import_on_upgrade')
196+ start_up.inner_start_up()
197+ self.expectThat(mock_start_import, MockCalledOnceWith())