Merge ~troyanov/maas:backport-21cf88e-3.5 into maas:3.5

Proposed by Anton Troyanov
Status: Merged
Approved by: Anton Troyanov
Approved revision: e67d48e2a4245b99a81d437a74d31333fe9bc6d2
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~troyanov/maas:backport-21cf88e-3.5
Merge into: maas:3.5
Diff against target: 289 lines (+150/-65)
2 files modified
src/maasserver/rpc/boot.py (+85/-58)
src/maasserver/rpc/tests/test_boot.py (+65/-7)
Reviewer Review Type Date Requested Status
Anton Troyanov Approve
Review via email: mp+462776@code.launchpad.net

Commit message

fix: get Ubuntu kernel for ephemeral deployments

fixes LP#2057939

(cherry picked from commit 21cf88e8a2f7855881728f965b7ca85ab59f4268)

To post a comment you must log in.
Revision history for this message
Anton Troyanov (troyanov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/rpc/boot.py b/src/maasserver/rpc/boot.py
2index cee4453..f04da81 100644
3--- a/src/maasserver/rpc/boot.py
4+++ b/src/maasserver/rpc/boot.py
5@@ -92,70 +92,95 @@ def event_log_pxe_request(machine, purpose):
6 )
7
8
9-def get_boot_filenames(
10- arch,
11- subarch,
12- osystem,
13- series,
14- commissioning_osystem=undefined,
15- commissioning_distro_series=undefined,
16-):
17- """Return the filenames of the kernel, initrd, and boot_dtb for the boot
18- resource."""
19- if subarch == "generic":
20- # MAAS doesn't store in the BootResource table what subarch is the
21- # generic subarch so lookup what the generic subarch maps to.
22- try:
23- boot_resource_subarch = get_working_kernel(
24- subarch,
25- None,
26- f"{arch}/{subarch}",
27- osystem,
28- series,
29- commissioning_osystem=commissioning_osystem,
30- commissioning_distro_series=commissioning_distro_series,
31- )
32- except ValidationError:
33- # It's possible that no kernel's exist at all for this arch,
34- # subarch, osystem, series combination. In that case just fallback
35- # to 'generic'.
36- boot_resource_subarch = "generic"
37- else:
38- boot_resource_subarch = subarch
39-
40+def _get_files_map(osystem, oseries, arch, subarch, exclude=None):
41+ exclude = exclude or []
42 try:
43- # Get the filename for the kernel, initrd, and boot_dtb the rack should
44- # use when booting.
45 boot_resource = BootResource.objects.get(
46- architecture=f"{arch}/{boot_resource_subarch}",
47- name=f"{osystem}/{series}",
48+ architecture=f"{arch}/{subarch}",
49+ name=f"{osystem}/{oseries}",
50 )
51- boot_resource_set = boot_resource.get_latest_complete_set()
52- boot_resource_files = {
53+ bset = boot_resource.get_latest_complete_set()
54+ return {
55 bfile.filetype: "/".join(
56 [
57 bfile.sha256,
58 osystem,
59 arch,
60- boot_resource_subarch,
61- series,
62- boot_resource_set.label,
63+ subarch,
64+ oseries,
65+ bset.label,
66 bfile.filename,
67 ]
68 )
69- for bfile in boot_resource_set.files.all()
70+ for bfile in bset.files.all()
71+ if bfile.filetype not in exclude
72 }
73 except ObjectDoesNotExist:
74+ return {}
75+
76+
77+def _xlate_generic_subarch(
78+ arch,
79+ subarch,
80+ kernel_osystem,
81+ kernel_release,
82+ commissioning_osystem,
83+ commissioning_distro_series,
84+):
85+ # MAAS doesn't store in the BootResource table what subarch is the
86+ # generic subarch so lookup what the generic subarch maps to.
87+ try:
88+ return get_working_kernel(
89+ subarch,
90+ None,
91+ f"{arch}/{subarch}",
92+ kernel_osystem,
93+ kernel_release,
94+ commissioning_osystem=commissioning_osystem,
95+ commissioning_distro_series=commissioning_distro_series,
96+ )
97+ except ValidationError:
98+ # It's possible that no kernel's exist at all for this arch,
99+ # subarch, osystem, series combination. In that case just fallback
100+ # to 'generic'.
101+ return "generic"
102+
103+
104+def get_boot_filenames(
105+ arch,
106+ subarch,
107+ osystem,
108+ series,
109+ commissioning_osystem=undefined,
110+ commissioning_distro_series=undefined,
111+):
112+ """Return the filenames of the kernel, initrd, and boot_dtb for the boot
113+ resource."""
114+ if subarch == "generic":
115+ kernel_subarch = _xlate_generic_subarch(
116+ arch,
117+ subarch,
118+ osystem,
119+ series,
120+ commissioning_osystem,
121+ commissioning_distro_series,
122+ )
123+ else:
124+ kernel_subarch = subarch
125+
126+ res_files = _get_files_map(osystem, series, arch, kernel_subarch)
127+ if not res_files and subarch != kernel_subarch:
128+ res_files = _get_files_map(osystem, series, arch, subarch)
129+
130+ if not res_files:
131 # If a filename can not be found return None to allow the rack to
132 # figure out what todo.
133 return None, None, None, None
134- kernel = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL, None)
135- initrd = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD, None)
136- boot_dtb = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_DTB, None)
137- if len(boot_resource_files) > 0:
138- rootfs = next(iter(boot_resource_files.values()))
139- else:
140- rootfs = None
141+
142+ kernel = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL, None)
143+ initrd = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD, None)
144+ boot_dtb = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_DTB, None)
145+ rootfs = next(iter(res_files.values()), None)
146 return kernel, initrd, boot_dtb, rootfs
147
148
149@@ -698,6 +723,15 @@ def get_config(
150 boot_purpose = get_final_boot_purpose(machine, arch, purpose)
151
152 kernel_osystem, kernel_release = osystem, series
153+
154+ kernel, initrd, boot_dtb, rootfs = get_boot_filenames(
155+ arch,
156+ subarch,
157+ osystem,
158+ series,
159+ commissioning_osystem=configs["commissioning_osystem"],
160+ commissioning_distro_series=configs["commissioning_distro_series"],
161+ )
162 # For custom image ephemeral deployments we use the default (ubuntu) commissioning os/distro kernel
163 if (
164 machine is not None
165@@ -708,16 +742,9 @@ def get_config(
166 configs["commissioning_osystem"],
167 configs["commissioning_distro_series"],
168 )
169-
170- # FIXME alexsander-souza: check the ephemeral deployment case
171- kernel, initrd, boot_dtb, rootfs = get_boot_filenames(
172- arch,
173- subarch,
174- osystem,
175- series,
176- commissioning_osystem=configs["commissioning_osystem"],
177- commissioning_distro_series=configs["commissioning_distro_series"],
178- )
179+ kernel, initrd, boot_dtb, _ = get_boot_filenames(
180+ arch, subarch, kernel_osystem, kernel_release
181+ )
182
183 # Return the params to the rack controller. Include the system_id only
184 # if the machine was known.
185diff --git a/src/maasserver/rpc/tests/test_boot.py b/src/maasserver/rpc/tests/test_boot.py
186index e041906..ea0cc64 100644
187--- a/src/maasserver/rpc/tests/test_boot.py
188+++ b/src/maasserver/rpc/tests/test_boot.py
189@@ -373,21 +373,29 @@ class TestGetConfig(MAASServerTestCase):
190 local_ip = factory.make_ip_address()
191 remote_ip = factory.make_ip_address()
192 node = self.make_node_with_extra(
193- status=NODE_STATUS.DEPLOYED, netboot=False, ephemeral_deploy=True
194+ status=NODE_STATUS.DEPLOYED,
195+ netboot=False,
196+ ephemeral_deploy=True,
197+ boot_cluster_ip=local_ip,
198+ osystem="centos",
199+ distro_series="8",
200 )
201- node.boot_cluster_ip = local_ip
202- node.osystem = "centos"
203- node.distro_series = "8"
204- node.architecture = "amd64/generic"
205- node.save()
206+ arch = node.architecture.split("/")[0]
207 mac = node.get_boot_interface().mac_address
208 self.patch_autospec(boot_module, "event_log_pxe_request")
209+ factory.make_default_ubuntu_release_bootable(arch=arch)
210+ factory.make_usable_boot_resource(
211+ name="centos/8",
212+ architecture=f"{arch}/generic",
213+ image_filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ,
214+ )
215+
216 config = get_config(
217 rack_controller.system_id, local_ip, remote_ip, mac=mac
218 )
219 self.assertEqual(config["osystem"], "centos")
220 self.assertEqual(config["release"], "8")
221- self.assertEqual(config["arch"], "amd64")
222+ self.assertEqual(config["arch"], arch)
223 self.assertEqual(config["subarch"], "generic")
224 self.assertEqual(
225 config["kernel_osystem"],
226@@ -398,6 +406,9 @@ class TestGetConfig(MAASServerTestCase):
227 Config.objects.get_config(name="commissioning_distro_series"),
228 )
229 self.assertEqual(config["purpose"], "xinstall")
230+ self.assertIn(f"/ubuntu/{arch}/hwe-", config["kernel"])
231+ self.assertIn(f"/ubuntu/{arch}/hwe-", config["initrd"])
232+ self.assertIn(f"/centos/{arch}/generic/8", config["xinstall_path"])
233
234 # See https://github.com/canonical/cloud-init/issues/4418 for more details
235 def test_preseed_url_not_using_domain_names_for_custom_ephemeral_deployments(
236@@ -1661,6 +1672,53 @@ class TestGetBootFilenames(MAASServerTestCase):
237 rootfs,
238 )
239
240+ def test_custom_deployment(self):
241+ architecture = make_usable_architecture(self)
242+ arch = architecture.split("/")[0]
243+ custom_res = factory.make_usable_boot_resource(
244+ name="centos/8",
245+ architecture=f"{arch}/generic",
246+ image_filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ,
247+ )
248+ custom_rset = custom_res.sets.first()
249+ kernel, initrd, _, rootfs = get_boot_filenames(
250+ arch,
251+ "generic",
252+ "centos",
253+ "8",
254+ )
255+
256+ self.assertEqual(
257+ self.composeURL(
258+ custom_res,
259+ custom_rset,
260+ custom_rset.files.get(
261+ filetype=BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL
262+ ),
263+ ),
264+ kernel,
265+ )
266+ self.assertEqual(
267+ self.composeURL(
268+ custom_res,
269+ custom_rset,
270+ custom_rset.files.get(
271+ filetype=BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD
272+ ),
273+ ),
274+ initrd,
275+ )
276+ self.assertEqual(
277+ self.composeURL(
278+ custom_res,
279+ custom_rset,
280+ custom_rset.files.get(
281+ filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ
282+ ),
283+ ),
284+ rootfs,
285+ )
286+
287 def test_get_filenames_finds_subarch_when_generic(self):
288 release = factory.make_default_ubuntu_release_bootable()
289 arch = release.architecture.split("/")[0]

Subscribers

People subscribed via source and target branches