Skip to content

Fix/guest os booting aarch64 ci#6872

Open
BulaYoungR wants to merge 3 commits into
autotest:masterfrom
BulaYoungR:fix/guest-os-booting-aarch64-ci
Open

Fix/guest os booting aarch64 ci#6872
BulaYoungR wants to merge 3 commits into
autotest:masterfrom
BulaYoungR:fix/guest-os-booting-aarch64-ci

Conversation

@BulaYoungR
Copy link
Copy Markdown

@BulaYoungR BulaYoungR commented May 13, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ARM64/AArch64-aware disk image downloading with automatic URL variant detection and prioritization
    • Introduced enhanced UEFI AArch64 boot configuration detection with automatic legacy format conversion
    • Added custom OVMF loader path resolution for improved cross-environment compatibility
    • Introduced configurable serial login timeout with platform-dependent defaults
  • Improvements

    • Enhanced boot element handling to prevent configuration conflicts
    • Improved error reporting for disk downloads with detailed attempt logs

Review Change Stack

Super User added 3 commits May 13, 2026 18:47
On UEFI virt guests, boot order appears on the disk device
(<boot order='1'/>) instead of <os><boot dev='hd'/>. Map the legacy
xpath when the host or params indicate AArch64/arm64, including
arm64-mmio machine types and nested os_xpath structures.

Use a regex for xpath matching, walk dict values, and log the
adapted os_xpath for debugging.

Committer: Bolatbek Issakh <bissakh@redhat.com>
Params often point custom_loader_path under /usr/share/edk2/ovmf/, which
does not exist on AArch64 hosts. Resolve to a writable path under the
Avocado data directory or /tmp, rewrite loader_dict paths to match,
makedirs before copy2, and surface OSError text on failure.

Fixes positive_test.customize_loader on arm64-mmio.

Committer: Bolatbek Issakh <bissakh@redhat.com>
Try multiple qcow2 URLs (arch-specific first on aarch64), optional
disk1_img_url_extra and longer download timeout. When os_attrs_boots
is set, clear conflicting per-disk boot/loadparm after os boots.
Extend serial login wait on aarch64 (default 480s, overridable via
serial_login_timeout).

Committer: Bolatbek Issakh <bissakh@redhat.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Walkthrough

This PR introduces AArch64 boot and firmware support enhancements across three test modules. It adds architecture detection to determine if a guest is ARM64-like, conditionally rewrites legacy OS boot XPath predicates to UEFI disk boot format, and generates multiple OVMF/AArch64 candidate URLs with retry-across-all logic. Boot configuration is cleaned to prevent conflicts, serial login timeouts are made platform-specific, and OVMF loader paths are validated with fallback to alternative writable directories when needed. All three modules also gain improved error reporting and logging.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix/guest os booting aarch64 ci' directly relates to the main changes, which involve OS-architecture-aware boot handling for AArch64 guests and CI improvements across three test modules.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py`:
- Around line 46-51: Replace uses of platform.machine() in this test with the
guest-arch parameters like params.get("arch"), params.get("vm_arch_name"),
params.get("machine_type") or params.get("shortname") (same pattern as
_guest_is_aarch64_arm64() in without_default_os_attributes.py); specifically,
change the image URL selection block (currently branching on platform.machine())
to detect the guest architecture from params and prefer aarch64 variants only
when the guest is aarch64, and also update the login timeout logic that uses
platform.machine() (around the later login timeout lines) to use the same
params-based guest-arch check so timeouts and image ordering reflect the guest,
not the host.

In
`@libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py`:
- Around line 80-81: Replace the insecure eval() call used to parse
params.get("os_xpath") with ast.literal_eval() to safely evaluate only Python
literal structures; update the os_xpath assignment passed to
_adapt_os_xpath_uefi_disk_boot by calling
ast.literal_eval(params.get("os_xpath")) and add/import the ast module at the
top of the file if missing, keeping the rest of the call (params, host_arch)
unchanged.

In `@libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py`:
- Around line 52-69: The fallback destinations for custom_loader_path use shared
basenames causing race/overwrite; change the branch that builds the alt
candidates to create a unique per-run path (e.g. use tempfile.mkdtemp() to make
a unique temp directory or tempfile.NamedTemporaryFile(delete=False) /
tempfile.mkstemp() to create a unique temp file) and join the basename into that
unique path before calling _replace_path_in_obj and returning; update the alt
variable used in the os.access check and loader_dict replacement so the
copy/cleanup uses this unique per-test path (referencing alt,
custom_loader_path, loader_dict, and _replace_path_in_obj).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c9cf29d2-ed73-49b1-a6cf-104ad4189821

📥 Commits

Reviewing files that changed from the base of the PR and between c96ab65 and a3a67c0.

📒 Files selected for processing (3)
  • libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py
  • libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py
  • libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py

Comment on lines +46 to +51
if platform.machine() == "aarch64":
# Prefer arch-named images first: generic URL may be x86-only
# and still HTTP-200, then guest never reaches login.
urls = aarch64_variants + [disk1_img_url, ovmf_url]
else:
urls = [ovmf_url, disk1_img_url] + aarch64_variants
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the file mentioned in the review
find . -name "boot_from_disk_device.py" -type f

Repository: autotest/tp-libvirt

Length of output: 136


🏁 Script executed:

# Also find the reference file
find . -name "without_default_os_attributes.py" -type f

Repository: autotest/tp-libvirt

Length of output: 150


🏁 Script executed:

# Get an overview of the repository structure
git ls-files | head -20

Repository: autotest/tp-libvirt

Length of output: 560


🏁 Script executed:

wc -l ./libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py

Repository: autotest/tp-libvirt

Length of output: 140


🏁 Script executed:

cat -n ./libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py

Repository: autotest/tp-libvirt

Length of output: 7333


🏁 Script executed:

wc -l ./libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py

Repository: autotest/tp-libvirt

Length of output: 154


🏁 Script executed:

cat -n ./libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py | head -80

Repository: autotest/tp-libvirt

Length of output: 2990


🏁 Script executed:

# Check what parameters are typically passed to these test functions
grep -r "arch\|machine_type\|shortname" ./libvirt/tests/src/guest_os_booting/boot_order/ | head -30

Repository: autotest/tp-libvirt

Length of output: 1935


🏁 Script executed:

# Look for how params are used in the guest_os_booting_base module
find . -name "guest_os_booting_base*" -type f

Repository: autotest/tp-libvirt

Length of output: 116


🏁 Script executed:

# Check if there are other files in the boot_order directory that might use similar logic
ls -la ./libvirt/tests/src/guest_os_booting/boot_order/

Repository: autotest/tp-libvirt

Length of output: 810


🏁 Script executed:

cat -n ./provider/guest_os_booting/guest_os_booting_base.py | head -100

Repository: autotest/tp-libvirt

Length of output: 3667


🏁 Script executed:

# Also check if there are any test configuration files that show how params work
find ./libvirt/tests -name "*.py" -type f -path "*guest_os_booting*" | xargs grep -l "arch\|machine_type" | head -5

Repository: autotest/tp-libvirt

Length of output: 437


🏁 Script executed:

# Let's also look for how params typically contains the guest arch info
grep -r "params.get.*arch\|params.get.*machine" ./libvirt/tests/src/guest_os_booting/ | head -10

Repository: autotest/tp-libvirt

Length of output: 509


Use guest architecture from params, not platform.machine().

The code currently uses host architecture for both image URL selection (lines 46-51) and login timeout (lines 152-153), which fails when the host and guest architectures differ. For example, on an x86_64 host running an aarch64 guest, the x86-only generic image would be downloaded first and cause boot/login failures.

The same test directory already has a working solution: _guest_is_aarch64_arm64() in without_default_os_attributes.py demonstrates the correct pattern using params.get("arch"), params.get("vm_arch_name"), params.get("machine_type"), and params.get("shortname"). Reuse that approach here to properly detect guest architecture.

🧰 Tools
🪛 Ruff (0.15.12)

[warning] 49-49: Consider [*aarch64_variants, disk1_img_url, ovmf_url] instead of concatenation

Replace with [*aarch64_variants, disk1_img_url, ovmf_url]

(RUF005)


[warning] 51-51: Consider [ovmf_url, disk1_img_url, *aarch64_variants] instead of concatenation

Replace with [ovmf_url, disk1_img_url, *aarch64_variants]

(RUF005)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py`
around lines 46 - 51, Replace uses of platform.machine() in this test with the
guest-arch parameters like params.get("arch"), params.get("vm_arch_name"),
params.get("machine_type") or params.get("shortname") (same pattern as
_guest_is_aarch64_arm64() in without_default_os_attributes.py); specifically,
change the image URL selection block (currently branching on platform.machine())
to detect the guest architecture from params and prefer aarch64 variants only
when the guest is aarch64, and also update the login timeout logic that uses
platform.machine() (around the later login timeout lines) to use the same
params-based guest-arch check so timeouts and image ordering reflect the guest,
not the host.

Comment on lines +80 to +81
os_xpath = _adapt_os_xpath_uefi_disk_boot(
eval(params.get("os_xpath")), params, host_arch)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Find and examine the file
fd -t f "without_default_os_attributes.py" libvirt/tests/src/

Repository: autotest/tp-libvirt

Length of output: 148


🏁 Script executed:

# Once found, look at lines around 80-81 with context
cat -n libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py | sed -n '70,95p'

Repository: autotest/tp-libvirt

Length of output: 1101


🏁 Script executed:

# Look for the _adapt_os_xpath_uefi_disk_boot function to understand what it expects
rg -n "_adapt_os_xpath_uefi_disk_boot" libvirt/tests/src/

Repository: autotest/tp-libvirt

Length of output: 351


🏁 Script executed:

# Look at the _adapt_os_xpath_uefi_disk_boot function definition
cat -n libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py | sed -n '41,70p'

Repository: autotest/tp-libvirt

Length of output: 1126


🏁 Script executed:

# Check imports at the top of the file
cat -n libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py | head -20

Repository: autotest/tp-libvirt

Length of output: 712


🏁 Script executed:

# Look for test parameters/config to see what os_xpath values look like
rg -n "os_xpath" libvirt/tests/src/guest_os_booting/os_configuration/ -A 2 -B 2

Repository: autotest/tp-libvirt

Length of output: 3734


Replace eval() with ast.literal_eval() to safely parse os_xpath parameter.

The current code executes arbitrary Python from configuration data, which is a security risk. Since _adapt_os_xpath_uefi_disk_boot() only processes literal Python values (strings, dicts, lists, tuples), ast.literal_eval() is the appropriate safe alternative.

Proposed fix
+import ast
 import platform
 import re
@@
-    os_xpath = _adapt_os_xpath_uefi_disk_boot(
-        eval(params.get("os_xpath")), params, host_arch)
+    os_xpath = _adapt_os_xpath_uefi_disk_boot(
+        ast.literal_eval(params.get("os_xpath")), params, host_arch)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
os_xpath = _adapt_os_xpath_uefi_disk_boot(
eval(params.get("os_xpath")), params, host_arch)
import ast
import platform
import re
...
os_xpath = _adapt_os_xpath_uefi_disk_boot(
ast.literal_eval(params.get("os_xpath")), params, host_arch)
🧰 Tools
🪛 Ruff (0.15.12)

[error] 81-81: Use of possibly insecure function; consider using ast.literal_eval

(S307)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@libvirt/tests/src/guest_os_booting/os_configuration/without_default_os_attributes.py`
around lines 80 - 81, Replace the insecure eval() call used to parse
params.get("os_xpath") with ast.literal_eval() to safely evaluate only Python
literal structures; update the os_xpath assignment passed to
_adapt_os_xpath_uefi_disk_boot by calling
ast.literal_eval(params.get("os_xpath")) and add/import the ast module at the
top of the file if missing, keeping the rest of the call (params, host_arch)
unchanged.

Comment on lines +52 to +69
for alt in (
os.path.join(data_dir.get_data_dir(), "images", os.path.basename(custom_loader_path)),
os.path.join(tempfile.gettempdir(), os.path.basename(custom_loader_path)),
):
parent = os.path.dirname(alt)
try:
os.makedirs(parent, exist_ok=True)
except OSError:
continue
if os.access(parent, os.W_OK):
test.log.info(
"custom_loader_path %r not usable (dir=%r); using %s instead",
custom_loader_path,
dest_dir,
alt,
)
loader_dict = _replace_path_in_obj(loader_dict, custom_loader_path, alt)
return alt, loader_dict
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the fallback loader path unique per test run.

These two candidates use shared filenames under images/ and /tmp/. Parallel jobs with the same custom_loader_path basename can overwrite each other here, and the unconditional cleanup later can delete another test's copied loader. Please switch this fallback to a per-run temp file or temp directory before rewriting loader_dict.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libvirt/tests/src/guest_os_booting/ovmf_firmware/ovmf_loader.py` around lines
52 - 69, The fallback destinations for custom_loader_path use shared basenames
causing race/overwrite; change the branch that builds the alt candidates to
create a unique per-run path (e.g. use tempfile.mkdtemp() to make a unique temp
directory or tempfile.NamedTemporaryFile(delete=False) / tempfile.mkstemp() to
create a unique temp file) and join the basename into that unique path before
calling _replace_path_in_obj and returning; update the alt variable used in the
os.access check and loader_dict replacement so the copy/cleanup uses this unique
per-test path (referencing alt, custom_loader_path, loader_dict, and
_replace_path_in_obj).

@harvey0100
Copy link
Copy Markdown

Closing this PR due to current team constraints. This is part of a broader effort to triage all in-flight work across our upstream repos. If this work is still needed, please feel free to reopen and it will be picked up. Apologies for any inconvenience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants