From 197c3f743dc1a23bc11064d99dc83d3de4a1cc1e Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Tue, 21 May 2024 15:36:01 -0600 Subject: [PATCH] fix: cloud-init datasource_list must be one-line Ensure datasource_list configuration from subiquity is a single line: datasource_list: [None] to support ds-identify limitation in parsing single-line datasource_list values. cloud-init's ds-identify doesn't actually support multi-line YAML and never has. We can see this behavior in /run/cloud-init/ds-identify.log which opts to use a default datsource_list and logs: /etcloud/cloud.cfg.d/99-installer.cfg set datasource_list: no datasource_list found, using default: .... This issue doesn't affect subiquity in practice because it also places /etc/cloud/ds-identify.cfg containing `policy: enabled`. Which means cloud-init will be enabled regardless of whether ds-identify finds a valid datasource. We see this in /run/cloud-init/ds-identify.log with the following: DSNAME= ... mode=enabled returning 0 Once cloud-init python code runs and merges system configuration in /etc/cloud/cloud.cfg.d with a proper YAML parser, it correctly parses multi-line YAML config and successfully limits the merged datasource_list: [ None ] provided in /etc/cloud/cloud.cfg.d/99-installer.yaml. If subiquity were to drop the /etc/cloud/ds-identify.cfg file in the future, cloud-init would actually be disabled on first boot because it never detected a viable datasource during systemd generator timeframe and ds-identify policy doesn't mandate being enabled by default. --- subiquity/models/subiquity.py | 5 ++++- subiquity/models/tests/test_subiquity.py | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/subiquity/models/subiquity.py b/subiquity/models/subiquity.py index 2d45e876..f0724202 100644 --- a/subiquity/models/subiquity.py +++ b/subiquity/models/subiquity.py @@ -435,7 +435,10 @@ class SubiquityModel: "metadata": metadata, }, }, - } + }, + # ds-identify does not support multi-line YAML datasource_list. + # Turn off default_flow_style forcing datasource_list: [None]. + default_flow_style=None, ) grub_dpkg = yaml.dump({"grub_dpkg": {"enabled": False}}) files = [ diff --git a/subiquity/models/tests/test_subiquity.py b/subiquity/models/tests/test_subiquity.py index b2ded689..0457fb20 100644 --- a/subiquity/models/tests/test_subiquity.py +++ b/subiquity/models/tests/test_subiquity.py @@ -285,7 +285,8 @@ grub_dpkg: enabled: false """, "etc/cloud/cloud.cfg.d/99-installer.cfg": re.compile( - "datasource:\n None:\n metadata:\n instance-id: .*\n userdata_raw: \"#cloud-config\\\\ngrowpart:\\\\n mode: \\'off\\'\\\\npreserve_hostname: true\\\\n\\\\\n" # noqa + "datasource:\n None:\n metadata: {instance-id: .*}\n userdata_raw: \"#cloud-config\\\\ngrowpart:\\\\n mode: \\'off\\'\\\\npreserve_hostname: true\\\\n\\\\\n.*datasource_list: \[None\]", # noqa + re.DOTALL, ), "etc/hostname": "somehost\n", "etc/cloud/ds-identify.cfg": "policy: enabled\n", @@ -320,7 +321,10 @@ grub_dpkg: ): for cpath, content, perms in model._cloud_init_files(): if isinstance(expected_files[cpath], re.Pattern): - self.assertIsNotNone(expected_files[cpath].match(content)) + self.assertIsNotNone( + expected_files[cpath].match(content), + f"Missing expected file match {cpath}: {content}" + ) else: self.assertEqual(expected_files[cpath], content)