diff --git a/doc/intro-to-autoinstall.rst b/doc/intro-to-autoinstall.rst index 79f5881e..ffb03a9c 100644 --- a/doc/intro-to-autoinstall.rst +++ b/doc/intro-to-autoinstall.rst @@ -78,24 +78,47 @@ Autoinstall on the install media Another option for supplying autoinstall to the Ubuntu installer is to place a file named :code:`autoinstall.yaml` on the install media itself. -There are two potential locations for the :code:`autoinstall.yaml` file: - * At the root of the "CD-ROM". When you write the installation ISO to a USB - Flash Drive, this can be done by copying the :code:`autoinstall.yaml` to the - partition containing the contents of the ISO - i.e., - in the directory containing the ``casper`` sub-directory. - * On the rootfs of the installation system - this option will typically - require modifying the installation ISO and is not suggested, but is - supported. +There are two potential locations that subiquity will check for the +:code:`autoinstall.yaml` file: -Directly specifying autoinstall as a :code:`autoinstall.yaml` file does not -require a :code:`#cloud-config` header, and does not use a top level -``autoinstall:`` key. The autoinstall directives are placed at the top -level. For example: +* At the root of the "CD-ROM". When you write the installation ISO to a USB + Flash Drive, this can be done by copying the :code:`autoinstall.yaml` to the + partition containing the contents of the ISO - i.e., + in the directory containing the ``casper`` sub-directory. +* On the rootfs of the installation system - this option will typically + require modifying the installation ISO and is not suggested, but is + supported. -.. code-block:: yaml +Alternatively, you can pass the location of the autoinstall file on the kernel +command line via the :code:`subiquity.autoinstallpath` parameter, where the +path is relative to the rootfs of the installation system. For example: - version: 1 - .... +* :code:`subiquity.autoinstallpath=path/to/autoinstall.yaml` + +.. note:: + + Directly specifying autoinstall as a :code:`autoinstall.yaml` file does not + require a :code:`#cloud-config` header, and does not use a top level + ``autoinstall:`` key. The autoinstall directives are placed at the top + level. For example: + + .. code-block:: yaml + + version: 1 + .... + + +Order precedence of the autoinstall locations +====================================== + +Since there are many ways to specify the autoinstall file, it may happen that +multiple locations are specified at once. Subiquity will look for the +autoinstall file in the following order and pick the first existing one: + +1. Kernel command line +2. Root of the installation system +3. Cloud Config +4. Root of the CD-ROM (ISO) Cloud-init and autoinstall interaction diff --git a/subiquity/server/server.py b/subiquity/server/server.py index 999d5fed..1cadce59 100644 --- a/subiquity/server/server.py +++ b/subiquity/server/server.py @@ -574,10 +574,11 @@ class SubiquityServer(Application): def select_autoinstall(self): # precedence - # 1. autoinstall at root of drive - # 2. command line argument autoinstall - # 3. autoinstall supplied by cloud config - # 4. autoinstall baked into the iso, found at /cdrom/autoinstall.yaml + # 1. command line argument autoinstall + # 2. kernel command line argument subiquity.autoinstallpath + # 3. autoinstall at root of drive + # 4. autoinstall supplied by cloud config + # 5. autoinstall baked into the iso, found at /cdrom/autoinstall.yaml # if opts.autoinstall is set and empty, that means # autoinstall has been explicitly disabled. @@ -588,9 +589,12 @@ class SubiquityServer(Application): ): raise Exception(f"Autoinstall argument {self.opts.autoinstall} not found") + kernel_install_path = self.kernel_cmdline.get("subiquity.autoinstallpath", None) + locations = ( - self.base_relative(root_autoinstall_path), self.opts.autoinstall, + kernel_install_path, + self.base_relative(root_autoinstall_path), self.base_relative(cloud_autoinstall_path), self.base_relative(iso_autoinstall_path), ) diff --git a/subiquity/server/tests/test_server.py b/subiquity/server/tests/test_server.py index 363e506f..60c40280 100644 --- a/subiquity/server/tests/test_server.py +++ b/subiquity/server/tests/test_server.py @@ -54,31 +54,46 @@ class TestAutoinstallLoad(SubiTestCase): return path def test_autoinstall_disabled(self): + self.server.opts.autoinstall = "" + self.server.kernel_cmdline = {"subiquity.autoinstallpath": "kernel"} self.create(root_autoinstall_path, "root") self.create(cloud_autoinstall_path, "cloud") self.create(iso_autoinstall_path, "iso") - self.server.opts.autoinstall = "" self.assertIsNone(self.server.select_autoinstall()) - def test_root_wins(self): - root = self.create(root_autoinstall_path, "root") - autoinstall = self.create(self.path("arg.autoinstall.yaml"), "arg") - self.server.opts.autoinstall = autoinstall - self.create(cloud_autoinstall_path, "cloud") - self.create(iso_autoinstall_path, "iso") - self.assertEqual(root, self.server.select_autoinstall()) - self.assert_contents(root, "root") - def test_arg_wins(self): - root = self.path(root_autoinstall_path) arg = self.create(self.path("arg.autoinstall.yaml"), "arg") self.server.opts.autoinstall = arg + kernel = self.create(self.path("kernel.autoinstall.yaml"), "kernel") + self.server.kernel_cmdline = {"subiquity.autoinstallpath": kernel} + root = self.create(root_autoinstall_path, "root") self.create(cloud_autoinstall_path, "cloud") self.create(iso_autoinstall_path, "iso") self.assertEqual(root, self.server.select_autoinstall()) self.assert_contents(root, "arg") + def test_kernel_wins(self): + self.server.opts.autoinstall = None + kernel = self.create(self.path("kernel.autoinstall.yaml"), "kernel") + self.server.kernel_cmdline = {"subiquity.autoinstallpath": kernel} + root = self.create(root_autoinstall_path, "root") + self.create(cloud_autoinstall_path, "cloud") + self.create(iso_autoinstall_path, "iso") + self.assertEqual(root, self.server.select_autoinstall()) + self.assert_contents(root, "kernel") + + def test_root_wins(self): + self.server.opts.autoinstall = None + self.server.kernel_cmdline = {} + root = self.create(root_autoinstall_path, "root") + self.create(cloud_autoinstall_path, "cloud") + self.create(iso_autoinstall_path, "iso") + self.assertEqual(root, self.server.select_autoinstall()) + self.assert_contents(root, "root") + def test_cloud_wins(self): + self.server.opts.autoinstall = None + self.server.kernel_cmdline = {} root = self.path(root_autoinstall_path) self.create(cloud_autoinstall_path, "cloud") self.create(iso_autoinstall_path, "iso") @@ -86,7 +101,10 @@ class TestAutoinstallLoad(SubiTestCase): self.assert_contents(root, "cloud") def test_iso_wins(self): + self.server.opts.autoinstall = None + self.server.kernel_cmdline = {} root = self.path(root_autoinstall_path) + # No cloud config file self.create(iso_autoinstall_path, "iso") self.assertEqual(root, self.server.select_autoinstall()) self.assert_contents(root, "iso")