Merge ~cgrabowski/maas:fix_lp1982866_3.1_backport into maas:3.1

Proposed by Christian Grabowski
Status: Merged
Approved by: Christian Grabowski
Approved revision: cd09b8b718cbbd68b07c4c9df9b3d7091e57c867
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~cgrabowski/maas:fix_lp1982866_3.1_backport
Merge into: maas:3.1
Diff against target: 316 lines (+187/-14)
6 files modified
src/maasserver/forms/__init__.py (+17/-4)
src/maasserver/forms/tests/test_bootresource.py (+40/-5)
src/maasserver/models/bootresource.py (+11/-0)
src/maasserver/models/tests/test_bootresource.py (+12/-0)
src/maasserver/rpc/boot.py (+1/-4)
src/maasserver/rpc/tests/test_boot.py (+106/-1)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
MAAS Maintainers Pending
Review via email: mp+430384@code.launchpad.net

Commit message

use BootResource's method for splitting base image to get a default value in get_boot_config_for_machine()
(cherry picked from commit d58366ec06df69f22273b72338e80e9459ee3f7c)

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b fix_lp1982866_3.1_backport lp:~cgrabowski/maas/+git/maas into -b 3.1 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/753/consoleText
COMMIT: 446f3819632f3ea854ba22bca64e59c2739031f6

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b fix_lp1982866_3.1_backport lp:~cgrabowski/maas/+git/maas into -b 3.1 lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas-tester/756/consoleText
COMMIT: cd09b8b718cbbd68b07c4c9df9b3d7091e57c867

review: Needs Fixing
Revision history for this message
Christian Grabowski (cgrabowski) wrote :

jenkins: !test

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b fix_lp1982866_3.1_backport lp:~cgrabowski/maas/+git/maas into -b 3.1 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: cd09b8b718cbbd68b07c4c9df9b3d7091e57c867

review: Approve
Revision history for this message
Christian Grabowski (cgrabowski) wrote :

self-approving backport

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py
index d88c443..2c0cf46 100644
--- a/src/maasserver/forms/__init__.py
+++ b/src/maasserver/forms/__init__.py
@@ -2493,7 +2493,7 @@ class BootResourceForm(MAASModelForm):
2493 return name2493 return name
24942494
2495 def _get_base_image_info(self):2495 def _get_base_image_info(self):
2496 base_image = self.cleaned_data["base_image"]2496 base_image = self.cleaned_data.get("base_image")
2497 if not base_image:2497 if not base_image:
2498 existing_resource = super().save(commit=False)2498 existing_resource = super().save(commit=False)
2499 existing_resource.name = self.cleaned_data["name"]2499 existing_resource.name = self.cleaned_data["name"]
@@ -2522,9 +2522,22 @@ class BootResourceForm(MAASModelForm):
2522 try:2522 try:
2523 base_osystem, base_version = self._get_base_image_info()2523 base_osystem, base_version = self._get_base_image_info()
2524 except ValueError:2524 except ValueError:
2525 raise ValidationError(2525 if not self.data.get("base_image"):
2526 "custom images require a valid base image name"2526 return "/".join(
2527 )2527 [
2528 val
2529 for val in Config.objects.get_configs(
2530 [
2531 "commissioning_osystem",
2532 "commissioning_distro_series",
2533 ]
2534 ).values()
2535 ]
2536 )
2537 else:
2538 raise ValidationError(
2539 "a base image must follow the format: <osystem>/<series>"
2540 )
2528 else:2541 else:
2529 if base_osystem not in ("ubuntu", "centos", "rhel"):2542 if base_osystem not in ("ubuntu", "centos", "rhel"):
2530 raise ValidationError(2543 raise ValidationError(
diff --git a/src/maasserver/forms/tests/test_bootresource.py b/src/maasserver/forms/tests/test_bootresource.py
index e8aaeec..4544a1d 100644
--- a/src/maasserver/forms/tests/test_bootresource.py
+++ b/src/maasserver/forms/tests/test_bootresource.py
@@ -10,7 +10,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
1010
11from maasserver.enum import BOOT_RESOURCE_FILE_TYPE, BOOT_RESOURCE_TYPE11from maasserver.enum import BOOT_RESOURCE_FILE_TYPE, BOOT_RESOURCE_TYPE
12from maasserver.forms import BootResourceForm12from maasserver.forms import BootResourceForm
13from maasserver.models import BootResource, BootResourceFile13from maasserver.models import BootResource, BootResourceFile, Config
14from maasserver.models.signals import bootresourcefiles, bootsources14from maasserver.models.signals import bootresourcefiles, bootsources
15from maasserver.testing.architecture import make_usable_architecture15from maasserver.testing.architecture import make_usable_architecture
16from maasserver.testing.factory import factory16from maasserver.testing.factory import factory
@@ -303,7 +303,7 @@ class TestBootResourceForm(MAASServerTestCase):
303 image = form.save()303 image = form.save()
304 self.assertEqual(image.base_image, data["base_image"])304 self.assertEqual(image.base_image, data["base_image"])
305305
306 def test_invalidates_nonexistent_custom_image_base_os(self):306 def test_uses_commissioning_os_for_nonexistent_custom_image_base_os(self):
307 name = "custom/%s" % factory.make_name("name")307 name = "custom/%s" % factory.make_name("name")
308 upload_type, filetype = self.pick_filetype()308 upload_type, filetype = self.pick_filetype()
309 size = random.randint(1024, 2048)309 size = random.randint(1024, 2048)
@@ -315,10 +315,17 @@ class TestBootResourceForm(MAASServerTestCase):
315 "title": factory.make_name("title"),315 "title": factory.make_name("title"),
316 "architecture": make_usable_architecture(self),316 "architecture": make_usable_architecture(self),
317 "filetype": upload_type,317 "filetype": upload_type,
318 "base_image": factory.make_name("invalid"),318 "base_image": "",
319 }319 }
320 form = BootResourceForm(data=data, files={"content": uploaded_file})320 form = BootResourceForm(data=data, files={"content": uploaded_file})
321 self.assertFalse(form.is_valid())321 form.save()
322 cfg = Config.objects.get_configs(
323 ["commissioning_osystem", "commissioning_distro_series"]
324 )
325 self.assertEqual(
326 f"{cfg['commissioning_osystem']}/{cfg['commissioning_distro_series']}",
327 form.instance.base_image,
328 )
322329
323 def test_invalidates_nonexistent_custom_image_base_os_no_prefix(self):330 def test_invalidates_nonexistent_custom_image_base_os_no_prefix(self):
324 name = factory.make_name("name")331 name = factory.make_name("name")
@@ -485,7 +492,7 @@ class TestBootResourceForm(MAASServerTestCase):
485 form = BootResourceForm(data={})492 form = BootResourceForm(data={})
486 self.assertFalse(form.is_valid(), form.errors)493 self.assertFalse(form.is_valid(), form.errors)
487 self.assertEqual(494 self.assertEqual(
488 {"name", "architecture", "filetype", "content", "base_image"},495 {"name", "architecture", "filetype", "content"},
489 form.errors.keys(),496 form.errors.keys(),
490 )497 )
491498
@@ -522,3 +529,31 @@ class TestBootResourceForm(MAASServerTestCase):
522 resource_set__resource=resource529 resource_set__resource=resource
523 ).count(),530 ).count(),
524 )531 )
532
533 def test_clean_base_image_sets_commissioning_osystem_and_distro_series_where_none_is_given(
534 self,
535 ):
536 architecture = make_usable_architecture(self)
537 upload_type, filetype = self.pick_filetype()
538 content = factory.make_string(1024).encode("utf-8")
539 upload_name = factory.make_name("filename")
540 uploaded_file = SimpleUploadedFile(content=content, name=upload_name)
541 data = {
542 "name": f"custom/{factory.make_name()}",
543 "architecture": architecture,
544 "filetype": upload_type,
545 }
546 form = BootResourceForm(data=data, files={"content": uploaded_file})
547 form.save()
548 cfg = Config.objects.get_configs(
549 ["commissioning_osystem", "commissioning_distro_series"]
550 )
551 self.assertEqual(
552 "/".join(
553 [
554 cfg["commissioning_osystem"],
555 cfg["commissioning_distro_series"],
556 ]
557 ),
558 form.instance.base_image,
559 )
diff --git a/src/maasserver/models/bootresource.py b/src/maasserver/models/bootresource.py
index 0c16c67..39b6a66 100644
--- a/src/maasserver/models/bootresource.py
+++ b/src/maasserver/models/bootresource.py
@@ -28,6 +28,7 @@ from maasserver.fields import JSONObjectField
28from maasserver.models.bootresourceset import BootResourceSet28from maasserver.models.bootresourceset import BootResourceSet
29from maasserver.models.bootsourcecache import BootSourceCache29from maasserver.models.bootsourcecache import BootSourceCache
30from maasserver.models.cleansave import CleanSave30from maasserver.models.cleansave import CleanSave
31from maasserver.models.config import Config
31from maasserver.models.timestampedmodel import now, TimestampedModel32from maasserver.models.timestampedmodel import now, TimestampedModel
32from maasserver.utils.orm import get_first, get_one33from maasserver.utils.orm import get_first, get_one
33from provisioningserver.drivers.osystem import OperatingSystemRegistry34from provisioningserver.drivers.osystem import OperatingSystemRegistry
@@ -582,6 +583,16 @@ class BootResource(CleanSave, TimestampedModel):
582 return self.architecture.split("/")583 return self.architecture.split("/")
583584
584 def split_base_image(self):585 def split_base_image(self):
586 # handle older custom images that may not have a base image
587 if not self.base_image:
588 cfg = Config.objects.get_configs(
589 ["commissioning_osystem", "commissioning_distro_series"]
590 )
591 return (
592 cfg["commissioning_osystem"],
593 cfg["commissioning_distro_series"],
594 )
595
585 return self.base_image.split("/")596 return self.base_image.split("/")
586597
587 def get_next_version_name(self):598 def get_next_version_name(self):
diff --git a/src/maasserver/models/tests/test_bootresource.py b/src/maasserver/models/tests/test_bootresource.py
index e4280b0..ba3dc71 100644
--- a/src/maasserver/models/tests/test_bootresource.py
+++ b/src/maasserver/models/tests/test_bootresource.py
@@ -21,6 +21,7 @@ from maasserver.models.bootresource import (
21 BootResource,21 BootResource,
22 RTYPE_REQUIRING_OS_SERIES_NAME,22 RTYPE_REQUIRING_OS_SERIES_NAME,
23)23)
24from maasserver.models.config import Config
24from maasserver.models.signals import bootsources25from maasserver.models.signals import bootsources
25from maasserver.testing.factory import factory26from maasserver.testing.factory import factory
26from maasserver.testing.testcase import MAASServerTestCase27from maasserver.testing.testcase import MAASServerTestCase
@@ -1155,3 +1156,14 @@ class TestBootResource(MAASServerTestCase):
1155 self.assertFalse(1156 self.assertFalse(
1156 resource.supports_subarch(factory.make_name("subarch"))1157 resource.supports_subarch(factory.make_name("subarch"))
1157 )1158 )
1159
1160 def test_split_base_image_handles_no_base_image(self):
1161 resource = factory.make_BootResource()
1162 resource.base_image = None
1163 cfg = Config.objects.get_configs(
1164 ["commissioning_osystem", "commissioning_distro_series"]
1165 )
1166 self.assertCountEqual(
1167 (cfg["commissioning_osystem"], cfg["commissioning_distro_series"]),
1168 resource.split_base_image(),
1169 )
diff --git a/src/maasserver/rpc/boot.py b/src/maasserver/rpc/boot.py
index 12f14b4..22f4102 100644
--- a/src/maasserver/rpc/boot.py
+++ b/src/maasserver/rpc/boot.py
@@ -231,10 +231,7 @@ def get_boot_config_for_machine(machine, configs, purpose):
231 install_image = None231 install_image = None
232 if osystem == "custom":232 if osystem == "custom":
233 install_image = BootResource.objects.get(name=series)233 install_image = BootResource.objects.get(name=series)
234 if install_image.base_image is not None:234 osystem, series = install_image.split_base_image()
235 # if the operating system is a custom ubuntu image,
236 # use the base image to install
237 osystem, series = install_image.base_image.split("/")
238235
239 if install_image is None or osystem != "ubuntu":236 if install_image is None or osystem != "ubuntu":
240 # Use only the commissioning osystem and series, for operating237 # Use only the commissioning osystem and series, for operating
diff --git a/src/maasserver/rpc/tests/test_boot.py b/src/maasserver/rpc/tests/test_boot.py
index 517dc8e..a0cae0d 100644
--- a/src/maasserver/rpc/tests/test_boot.py
+++ b/src/maasserver/rpc/tests/test_boot.py
@@ -24,7 +24,11 @@ from maasserver.models.timestampedmodel import now
24from maasserver.node_status import get_node_timeout, MONITORED_STATUSES24from maasserver.node_status import get_node_timeout, MONITORED_STATUSES
25from maasserver.preseed import compose_enlistment_preseed_url25from maasserver.preseed import compose_enlistment_preseed_url
26from maasserver.rpc import boot as boot_module26from maasserver.rpc import boot as boot_module
27from maasserver.rpc.boot import event_log_pxe_request, get_boot_filenames27from maasserver.rpc.boot import (
28 event_log_pxe_request,
29 get_boot_config_for_machine,
30 get_boot_filenames,
31)
28from maasserver.rpc.boot import get_config as orig_get_config32from maasserver.rpc.boot import get_config as orig_get_config
29from maasserver.rpc.boot import merge_kparams_with_extra33from maasserver.rpc.boot import merge_kparams_with_extra
30from maasserver.testing.architecture import make_usable_architecture34from maasserver.testing.architecture import make_usable_architecture
@@ -1520,3 +1524,104 @@ class TestGetBootFilenames(MAASServerTestCase):
1520 initrd,1524 initrd,
1521 )1525 )
1522 self.assertIsNone(boot_dbt)1526 self.assertIsNone(boot_dbt)
1527
1528
1529class TestGetBootConfigForMachine(MAASServerTestCase):
1530 def test_get_boot_config_for_machine_builtin_image(self):
1531 machine = factory.make_Machine(
1532 status=NODE_STATUS.DEPLOYING,
1533 osystem="ubuntu",
1534 distro_series="focal",
1535 )
1536 configs = Config.objects.get_configs(
1537 [
1538 "commissioning_osystem",
1539 "commissioning_distro_series",
1540 "enable_third_party_drivers",
1541 "default_min_hwe_kernel",
1542 "default_osystem",
1543 "default_distro_series",
1544 "kernel_opts",
1545 "use_rack_proxy",
1546 "maas_internal_domain",
1547 "remote_syslog",
1548 "maas_syslog_port",
1549 ]
1550 )
1551
1552 osystem, series, config_arch = get_boot_config_for_machine(
1553 machine, configs, "xinstall"
1554 )
1555
1556 self.assertEqual(osystem, "ubuntu")
1557 self.assertEqual(series, "focal")
1558 self.assertEqual(config_arch, "generic")
1559
1560 def test_get_boot_config_for_machine_new_custom_image(self):
1561 arch = make_usable_architecture(self)
1562 boot_resource = factory.make_BootResource(
1563 base_image="ubuntu/jammy", architecture=arch
1564 )
1565 machine = factory.make_Machine(
1566 status=NODE_STATUS.DEPLOYING,
1567 osystem="custom",
1568 distro_series=boot_resource.name,
1569 )
1570 configs = Config.objects.get_configs(
1571 [
1572 "commissioning_osystem",
1573 "commissioning_distro_series",
1574 "enable_third_party_drivers",
1575 "default_min_hwe_kernel",
1576 "default_osystem",
1577 "default_distro_series",
1578 "kernel_opts",
1579 "use_rack_proxy",
1580 "maas_internal_domain",
1581 "remote_syslog",
1582 "maas_syslog_port",
1583 ]
1584 )
1585
1586 osystem, series, config_arch = get_boot_config_for_machine(
1587 machine, configs, "xinstall"
1588 )
1589
1590 self.assertEqual(osystem, "ubuntu")
1591 self.assertEqual(series, "jammy")
1592 self.assertEqual(config_arch, "generic")
1593
1594 def test_get_boot_config_for_machine_legacy_custom_image(self):
1595 arch = make_usable_architecture(self)
1596 boot_resource = factory.make_BootResource(
1597 base_image="", architecture=arch
1598 )
1599 machine = factory.make_Machine(
1600 status=NODE_STATUS.DEPLOYING,
1601 osystem="custom",
1602 distro_series=boot_resource.name,
1603 )
1604 configs = Config.objects.get_configs(
1605 [
1606 "commissioning_osystem",
1607 "commissioning_distro_series",
1608 "enable_third_party_drivers",
1609 "default_min_hwe_kernel",
1610 "default_osystem",
1611 "default_distro_series",
1612 "kernel_opts",
1613 "use_rack_proxy",
1614 "maas_internal_domain",
1615 "remote_syslog",
1616 "maas_syslog_port",
1617 ]
1618 )
1619
1620 osystem, series, config_arch = get_boot_config_for_machine(
1621 machine, configs, "xinstall"
1622 )
1623
1624 # legacy custom images should use the default commissioning image as a base image
1625 self.assertEqual(osystem, configs["commissioning_osystem"])
1626 self.assertEqual(series, configs["commissioning_distro_series"])
1627 self.assertEqual(config_arch, "generic")

Subscribers

People subscribed via source and target branches