Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: support for live ISOs to zapper_kvm connector #303

Merged
merged 8 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

Zapper-driven provisioning method that makes use of KVM assertions and actions.

## Ubuntu Desktop / Server

## Autoinstall based

Support for vanilla Ubuntu is provided by [autoinstall](https://canonical-subiquity.readthedocs-hosted.com/en/latest/intro-to-autoinstall.html). Supported Ubuntu versions are:

- Core24 (experimental)
- Desktop >= 23.04
- Server >= 20.04

Expand All @@ -16,7 +18,7 @@ Unless specified via _autoinstall_ storage filter, the tool will select the larg
- __url__: URL to the image to install
- __username__: username to configure
- __password__: password to configure
- **storage_layout**: can be either `lvm`, `direct`, `zfs` or `hybrid` (Desktop 23.10+)
- **storage_layout**: can be either `lvm`, `direct`, `zfs` or `hybrid` (Core, Desktop 23.10+)
- **robot_tasks**: list of Zapper Robot tasks to run after a hard reset in order to follow the `autoinstall` installation
- **cmdline_append** (optional): kernel parameters to append at the end of GRUB entry cmdline
- **base_user_data** (optional): a custom base user-data file, it should be validated against [this schema](https://canonical-subiquity.readthedocs-hosted.com/en/latest/reference/autoinstall-schema.html)
Expand Down Expand Up @@ -46,3 +48,13 @@ The tool will select the storage device with the following priority:
### Noble

Ubuntu OEM 24.04 uses `autoinstall`. The procedure and the arguments are the same as _vanilla_ Ubuntu.

## Live ISO

Support for live ISOs is simply performed booting from an external storage device and returning right after KVM interactions.
p-gentili marked this conversation as resolved.
Show resolved Hide resolved

### Job parameters

- __boot_from_ext_media__: Set to "true" to ensure that the Zapper considers the provision process complete at the end of KVM interactions, without needing to unplug the external media.
- __wait_until_ssh__: If set to "true", the Zapper will skip the SSH connection attempt, which is normally performed at the end of provisioning as a form of boot assertion. This is primarily useful in cases where the live ISO does not include an SSH server.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import logging
import os
import subprocess
from typing import Any, Dict, Tuple
from typing import Any, Dict, Optional, Tuple

from testflinger_device_connectors.devices import ProvisioningError
from testflinger_device_connectors.devices.zapper import ZapperConnector
Expand All @@ -36,14 +36,14 @@ class DeviceConnector(ZapperConnector):

PROVISION_METHOD = "ProvisioningKVM"

def _get_autoinstall_conf(self) -> Dict[str, Any]:
def _get_autoinstall_conf(self) -> Optional[Dict[str, Any]]:
"""Prepare autoinstall-related configuration."""
provision = self.job_data["provision_data"]

autoinstall_conf = {
"storage_layout": provision.get("storage_layout", "lvm"),
}
if "storage_layout" not in provision:
return None

autoinstall_conf = {"storage_layout": provision["storage_layout"]}
if "base_user_data" in provision:
autoinstall_conf["base_user_data"] = provision["base_user_data"]

Expand Down Expand Up @@ -81,19 +81,29 @@ def _validate_configuration(
"url": url,
"username": username,
"password": password,
"robot_retries": retries,
"autoinstall_conf": self._get_autoinstall_conf(),
"reboot_script": self.config["reboot_script"],
"device_ip": self.config["device_ip"],
"robot_tasks": self.job_data["provision_data"]["robot_tasks"],
"robot_retries": retries,
"cmdline_append": self.job_data["provision_data"].get(
"cmdline_append", ""
),
"skip_download": self.job_data["provision_data"].get(
"skip_download", False
),
}

# Let's handle defaults on the Zapper side adding only the explicitely
p-gentili marked this conversation as resolved.
Show resolved Hide resolved
# specified keys to the `provision_data` dict.
optionals = [
"cmdline_append",
"skip_download",
"wait_until_ssh",
"boot_from_ext_media",
]
provisioning_data.update(
{
opt: self.job_data["provision_data"][opt]
for opt in optionals
if opt in self.job_data["provision_data"]
}
)

return ((), provisioning_data)

def _post_run_actions(self, args):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ def test_validate_configuration(self):
"device_ip": "1.1.1.1",
"robot_tasks": ["job.robot", "another.robot"],
"robot_retries": 1,
"cmdline_append": "",
"skip_download": False,
}
self.assertEqual(args, ())
self.assertDictEqual(kwargs, expected)
Expand Down Expand Up @@ -90,6 +88,8 @@ def test_validate_configuration_w_opt(self):
"robot_retries": 3,
"cmdline_append": "more arguments",
"skip_download": True,
"wait_until_ssh": True,
"boot_from_ext_media": False,
},
"test_data": {
"test_username": "username",
Expand All @@ -111,6 +111,8 @@ def test_validate_configuration_w_opt(self):
"robot_retries": 3,
"cmdline_append": "more arguments",
"skip_download": True,
"wait_until_ssh": True,
"boot_from_ext_media": False,
}
self.assertEqual(args, ())
self.assertDictEqual(kwargs, expected)
Expand Down Expand Up @@ -159,12 +161,37 @@ def test_validate_configuration_alloem(self):
"device_ip": "1.1.1.1",
"robot_tasks": ["job.robot", "another.robot"],
"robot_retries": 2,
"cmdline_append": "",
"skip_download": False,
}
self.assertEqual(args, ())
self.assertDictEqual(kwargs, expected)

def test_get_autoinstall_none(self):
"""
Test whether the get_autoinstall_conf function returns
None in case the storage_layout is not specified.
"""

connector = DeviceConnector()
connector.job_data = {
"job_queue": "queue",
"provision_data": {
"url": "http://example.com/image.iso",
"robot_tasks": [
"job.robot",
"another.robot",
],
},
"test_data": {
"test_username": "username",
"test_password": "password",
},
}

with patch("builtins.open", mock_open(read_data="mykey")):
conf = connector._get_autoinstall_conf()

self.assertIsNone(conf)

def test_get_autoinstall_conf(self):
"""
Test whether the get_autoinstall_conf function returns
Expand Down
1 change: 1 addition & 0 deletions docs/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Git
GitHub
Grafana
IAM
ISOs
init
installable
Instantiation
Expand Down
19 changes: 18 additions & 1 deletion docs/reference/device-connector-types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ The ``zapper_kvm`` device connector, depending on the target image, supports the
path from the ``robot/snippets`` path in the Zapper repository.
* - ``storage_layout``
- When provisioning an image supporting *autoinstall*, the storage_layout can
be either ``lvm`` (default), ``direct``, ``zfs`` or ``hybrid`` (Desktop 23.10+)
be either ``lvm`` (default), ``direct``, ``zfs`` or ``hybrid`` (Core, Desktop 23.10+)
* - ``cmdline_append``
- When provisioning an image supporting *autoinstall*, the cmdline_append can
be used to append Kernel parameters to the standard GRUB entry.
Expand Down Expand Up @@ -314,3 +314,20 @@ The ``zapper_kvm`` device connector, depending on the target image, supports the
* - ``oem``
- Optional value to select the ``oemscript`` to run when specifying a ``url``, possible values
are ``dell``, ``hp`` and ``lenovo``.

.. list-table:: Supported ``provision_data`` keys for ``zapper_kvm`` with target any generic live ISOs
:header-rows: 1

* - Key
- Description
* - ``url``
- URL to a disk image that is downloaded and flashed to a USB storage device,
which will be used to boot up the DUT.
p-gentili marked this conversation as resolved.
Show resolved Hide resolved
* - ``robot_tasks``
- List of Zapper/Robot snippets to run in sequence after the USB storage device
p-gentili marked this conversation as resolved.
Show resolved Hide resolved
is plugged into the DUT and the system restarted. The snippet ID is the relative
path from the ``robot/snippets`` path in the Zapper repository.
* - ``boot_from_ext_media``
- Set to "true" to ensure that the Zapper considers the provision process complete at the end of KVM interactions, without needing to unplug the external media.
p-gentili marked this conversation as resolved.
Show resolved Hide resolved
* - ``wait_until_ssh``
- If set to "true", the Zapper will skip the SSH connection attempt, which is normally performed at the end of provisioning as a form of boot assertion. This is primarily useful in cases where the live ISO does not include an SSH server.