From 250280ada67995a8449b64027b879d01939d2729 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Mon, 10 Apr 2023 21:57:09 -0600 Subject: Fix NoCloud kernel commandline semi-colon args Truncate any trailing semi-colon delimited kernel commandline parameters when trying to match the designated datasource from /proc/cmdline. This was broken in 612b4de892d on systemd systems. Add an integration test for this codepath. --- .../test_kernel_commandline_match.py | 25 ++++++++++++++++------ tools/ds-identify | 3 +++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/integration_tests/test_kernel_commandline_match.py b/tests/integration_tests/test_kernel_commandline_match.py index af1e305f..cbbce9ca 100644 --- a/tests/integration_tests/test_kernel_commandline_match.py +++ b/tests/integration_tests/test_kernel_commandline_match.py @@ -14,11 +14,24 @@ def override_kernel_cmdline(ds_str: str, c: IntegrationInstance) -> str: Ironic, for example, it will succeed. """ client = c - client.execute( - "sed --in-place " - "'s/^.*GRUB_CMDLINE_LINUX=.*$/GRUB_CMDLINE_LINUX=\"" + ds_str + '"/g' - "' /etc/default/grub" - ) + + # The final output in /etc/default/grub should be: + # + # GRUB_CMDLINE_LINUX="'ds=nocloud;s=http://my-url/'" + # + # That ensures that the kernel commandline passed into + # /boot/efi/EFI/ubuntu/grub.cfg will be properly single-quoted + # + # Example: + # + # linux /boot/vmlinuz-5.15.0-1030-kvm ro 'ds=nocloud;s=http://my-url/' + # + # Not doing this will result in a semicolon-delimited ds argument + # terminating the kernel arguments prematurely. + client.execute('printf "GRUB_CMDLINE_LINUX=\\"" >> /etc/default/grub') + client.execute('printf "\'" >> /etc/default/grub') + client.execute(f"printf '{ds_str}' >> /etc/default/grub") + client.execute('printf "\'\\"" >> /etc/default/grub') # We should probably include non-systemd distros at some point. This should # most likely be as simple as updating the output path for grub-mkconfig @@ -36,7 +49,7 @@ def override_kernel_cmdline(ds_str: str, c: IntegrationInstance) -> str: @pytest.mark.parametrize( "ds_str, configured", ( - ("ds=nocloud", "DataSourceNoCloud"), + ("ds=nocloud;s=http://my-url/", "DataSourceNoCloud"), ("ci.ds=openstack", "DataSourceOpenStack"), ), ) diff --git a/tools/ds-identify b/tools/ds-identify index 1a94c9ab..bac385dc 100755 --- a/tools/ds-identify +++ b/tools/ds-identify @@ -1739,6 +1739,9 @@ read_config() { for tok in ${DI_KERNEL_CMDLINE}; do key=${tok%%=*} val=${tok#*=} + + # discard anything after delimiter + val=${val%;*} case "$key" in ds) _rc_dsname="$val";; ci.ds) _rc_dsname="$val";; -- cgit v1.2.1