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
diff --git a/src/maasserver/rpc/boot.py b/src/maasserver/rpc/boot.py
index cee4453..f04da81 100644
--- a/src/maasserver/rpc/boot.py
+++ b/src/maasserver/rpc/boot.py
@@ -92,70 +92,95 @@ def event_log_pxe_request(machine, purpose):
92 )92 )
9393
9494
95def get_boot_filenames(95def _get_files_map(osystem, oseries, arch, subarch, exclude=None):
96 arch,96 exclude = exclude or []
97 subarch,
98 osystem,
99 series,
100 commissioning_osystem=undefined,
101 commissioning_distro_series=undefined,
102):
103 """Return the filenames of the kernel, initrd, and boot_dtb for the boot
104 resource."""
105 if subarch == "generic":
106 # MAAS doesn't store in the BootResource table what subarch is the
107 # generic subarch so lookup what the generic subarch maps to.
108 try:
109 boot_resource_subarch = get_working_kernel(
110 subarch,
111 None,
112 f"{arch}/{subarch}",
113 osystem,
114 series,
115 commissioning_osystem=commissioning_osystem,
116 commissioning_distro_series=commissioning_distro_series,
117 )
118 except ValidationError:
119 # It's possible that no kernel's exist at all for this arch,
120 # subarch, osystem, series combination. In that case just fallback
121 # to 'generic'.
122 boot_resource_subarch = "generic"
123 else:
124 boot_resource_subarch = subarch
125
126 try:97 try:
127 # Get the filename for the kernel, initrd, and boot_dtb the rack should
128 # use when booting.
129 boot_resource = BootResource.objects.get(98 boot_resource = BootResource.objects.get(
130 architecture=f"{arch}/{boot_resource_subarch}",99 architecture=f"{arch}/{subarch}",
131 name=f"{osystem}/{series}",100 name=f"{osystem}/{oseries}",
132 )101 )
133 boot_resource_set = boot_resource.get_latest_complete_set()102 bset = boot_resource.get_latest_complete_set()
134 boot_resource_files = {103 return {
135 bfile.filetype: "/".join(104 bfile.filetype: "/".join(
136 [105 [
137 bfile.sha256,106 bfile.sha256,
138 osystem,107 osystem,
139 arch,108 arch,
140 boot_resource_subarch,109 subarch,
141 series,110 oseries,
142 boot_resource_set.label,111 bset.label,
143 bfile.filename,112 bfile.filename,
144 ]113 ]
145 )114 )
146 for bfile in boot_resource_set.files.all()115 for bfile in bset.files.all()
116 if bfile.filetype not in exclude
147 }117 }
148 except ObjectDoesNotExist:118 except ObjectDoesNotExist:
119 return {}
120
121
122def _xlate_generic_subarch(
123 arch,
124 subarch,
125 kernel_osystem,
126 kernel_release,
127 commissioning_osystem,
128 commissioning_distro_series,
129):
130 # MAAS doesn't store in the BootResource table what subarch is the
131 # generic subarch so lookup what the generic subarch maps to.
132 try:
133 return get_working_kernel(
134 subarch,
135 None,
136 f"{arch}/{subarch}",
137 kernel_osystem,
138 kernel_release,
139 commissioning_osystem=commissioning_osystem,
140 commissioning_distro_series=commissioning_distro_series,
141 )
142 except ValidationError:
143 # It's possible that no kernel's exist at all for this arch,
144 # subarch, osystem, series combination. In that case just fallback
145 # to 'generic'.
146 return "generic"
147
148
149def get_boot_filenames(
150 arch,
151 subarch,
152 osystem,
153 series,
154 commissioning_osystem=undefined,
155 commissioning_distro_series=undefined,
156):
157 """Return the filenames of the kernel, initrd, and boot_dtb for the boot
158 resource."""
159 if subarch == "generic":
160 kernel_subarch = _xlate_generic_subarch(
161 arch,
162 subarch,
163 osystem,
164 series,
165 commissioning_osystem,
166 commissioning_distro_series,
167 )
168 else:
169 kernel_subarch = subarch
170
171 res_files = _get_files_map(osystem, series, arch, kernel_subarch)
172 if not res_files and subarch != kernel_subarch:
173 res_files = _get_files_map(osystem, series, arch, subarch)
174
175 if not res_files:
149 # If a filename can not be found return None to allow the rack to176 # If a filename can not be found return None to allow the rack to
150 # figure out what todo.177 # figure out what todo.
151 return None, None, None, None178 return None, None, None, None
152 kernel = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL, None)179
153 initrd = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD, None)180 kernel = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL, None)
154 boot_dtb = boot_resource_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_DTB, None)181 initrd = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD, None)
155 if len(boot_resource_files) > 0:182 boot_dtb = res_files.pop(BOOT_RESOURCE_FILE_TYPE.BOOT_DTB, None)
156 rootfs = next(iter(boot_resource_files.values()))183 rootfs = next(iter(res_files.values()), None)
157 else:
158 rootfs = None
159 return kernel, initrd, boot_dtb, rootfs184 return kernel, initrd, boot_dtb, rootfs
160185
161186
@@ -698,6 +723,15 @@ def get_config(
698 boot_purpose = get_final_boot_purpose(machine, arch, purpose)723 boot_purpose = get_final_boot_purpose(machine, arch, purpose)
699724
700 kernel_osystem, kernel_release = osystem, series725 kernel_osystem, kernel_release = osystem, series
726
727 kernel, initrd, boot_dtb, rootfs = get_boot_filenames(
728 arch,
729 subarch,
730 osystem,
731 series,
732 commissioning_osystem=configs["commissioning_osystem"],
733 commissioning_distro_series=configs["commissioning_distro_series"],
734 )
701 # For custom image ephemeral deployments we use the default (ubuntu) commissioning os/distro kernel735 # For custom image ephemeral deployments we use the default (ubuntu) commissioning os/distro kernel
702 if (736 if (
703 machine is not None737 machine is not None
@@ -708,16 +742,9 @@ def get_config(
708 configs["commissioning_osystem"],742 configs["commissioning_osystem"],
709 configs["commissioning_distro_series"],743 configs["commissioning_distro_series"],
710 )744 )
711745 kernel, initrd, boot_dtb, _ = get_boot_filenames(
712 # FIXME alexsander-souza: check the ephemeral deployment case746 arch, subarch, kernel_osystem, kernel_release
713 kernel, initrd, boot_dtb, rootfs = get_boot_filenames(747 )
714 arch,
715 subarch,
716 osystem,
717 series,
718 commissioning_osystem=configs["commissioning_osystem"],
719 commissioning_distro_series=configs["commissioning_distro_series"],
720 )
721748
722 # Return the params to the rack controller. Include the system_id only749 # Return the params to the rack controller. Include the system_id only
723 # if the machine was known.750 # if the machine was known.
diff --git a/src/maasserver/rpc/tests/test_boot.py b/src/maasserver/rpc/tests/test_boot.py
index e041906..ea0cc64 100644
--- a/src/maasserver/rpc/tests/test_boot.py
+++ b/src/maasserver/rpc/tests/test_boot.py
@@ -373,21 +373,29 @@ class TestGetConfig(MAASServerTestCase):
373 local_ip = factory.make_ip_address()373 local_ip = factory.make_ip_address()
374 remote_ip = factory.make_ip_address()374 remote_ip = factory.make_ip_address()
375 node = self.make_node_with_extra(375 node = self.make_node_with_extra(
376 status=NODE_STATUS.DEPLOYED, netboot=False, ephemeral_deploy=True376 status=NODE_STATUS.DEPLOYED,
377 netboot=False,
378 ephemeral_deploy=True,
379 boot_cluster_ip=local_ip,
380 osystem="centos",
381 distro_series="8",
377 )382 )
378 node.boot_cluster_ip = local_ip383 arch = node.architecture.split("/")[0]
379 node.osystem = "centos"
380 node.distro_series = "8"
381 node.architecture = "amd64/generic"
382 node.save()
383 mac = node.get_boot_interface().mac_address384 mac = node.get_boot_interface().mac_address
384 self.patch_autospec(boot_module, "event_log_pxe_request")385 self.patch_autospec(boot_module, "event_log_pxe_request")
386 factory.make_default_ubuntu_release_bootable(arch=arch)
387 factory.make_usable_boot_resource(
388 name="centos/8",
389 architecture=f"{arch}/generic",
390 image_filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ,
391 )
392
385 config = get_config(393 config = get_config(
386 rack_controller.system_id, local_ip, remote_ip, mac=mac394 rack_controller.system_id, local_ip, remote_ip, mac=mac
387 )395 )
388 self.assertEqual(config["osystem"], "centos")396 self.assertEqual(config["osystem"], "centos")
389 self.assertEqual(config["release"], "8")397 self.assertEqual(config["release"], "8")
390 self.assertEqual(config["arch"], "amd64")398 self.assertEqual(config["arch"], arch)
391 self.assertEqual(config["subarch"], "generic")399 self.assertEqual(config["subarch"], "generic")
392 self.assertEqual(400 self.assertEqual(
393 config["kernel_osystem"],401 config["kernel_osystem"],
@@ -398,6 +406,9 @@ class TestGetConfig(MAASServerTestCase):
398 Config.objects.get_config(name="commissioning_distro_series"),406 Config.objects.get_config(name="commissioning_distro_series"),
399 )407 )
400 self.assertEqual(config["purpose"], "xinstall")408 self.assertEqual(config["purpose"], "xinstall")
409 self.assertIn(f"/ubuntu/{arch}/hwe-", config["kernel"])
410 self.assertIn(f"/ubuntu/{arch}/hwe-", config["initrd"])
411 self.assertIn(f"/centos/{arch}/generic/8", config["xinstall_path"])
401412
402 # See https://github.com/canonical/cloud-init/issues/4418 for more details413 # See https://github.com/canonical/cloud-init/issues/4418 for more details
403 def test_preseed_url_not_using_domain_names_for_custom_ephemeral_deployments(414 def test_preseed_url_not_using_domain_names_for_custom_ephemeral_deployments(
@@ -1661,6 +1672,53 @@ class TestGetBootFilenames(MAASServerTestCase):
1661 rootfs,1672 rootfs,
1662 )1673 )
16631674
1675 def test_custom_deployment(self):
1676 architecture = make_usable_architecture(self)
1677 arch = architecture.split("/")[0]
1678 custom_res = factory.make_usable_boot_resource(
1679 name="centos/8",
1680 architecture=f"{arch}/generic",
1681 image_filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ,
1682 )
1683 custom_rset = custom_res.sets.first()
1684 kernel, initrd, _, rootfs = get_boot_filenames(
1685 arch,
1686 "generic",
1687 "centos",
1688 "8",
1689 )
1690
1691 self.assertEqual(
1692 self.composeURL(
1693 custom_res,
1694 custom_rset,
1695 custom_rset.files.get(
1696 filetype=BOOT_RESOURCE_FILE_TYPE.BOOT_KERNEL
1697 ),
1698 ),
1699 kernel,
1700 )
1701 self.assertEqual(
1702 self.composeURL(
1703 custom_res,
1704 custom_rset,
1705 custom_rset.files.get(
1706 filetype=BOOT_RESOURCE_FILE_TYPE.BOOT_INITRD
1707 ),
1708 ),
1709 initrd,
1710 )
1711 self.assertEqual(
1712 self.composeURL(
1713 custom_res,
1714 custom_rset,
1715 custom_rset.files.get(
1716 filetype=BOOT_RESOURCE_FILE_TYPE.ROOT_TGZ
1717 ),
1718 ),
1719 rootfs,
1720 )
1721
1664 def test_get_filenames_finds_subarch_when_generic(self):1722 def test_get_filenames_finds_subarch_when_generic(self):
1665 release = factory.make_default_ubuntu_release_bootable()1723 release = factory.make_default_ubuntu_release_bootable()
1666 arch = release.architecture.split("/")[0]1724 arch = release.architecture.split("/")[0]

Subscribers

People subscribed via source and target branches