How VirtTestOptionsProcess Handles VT-Specific Command-Line Options in Avocado-VT

The VirtTestOptionsProcess class in avocado_vt/options.py translates VT-specific command-line flags like --vt-type and --vt-qemu-bin into a cartesian configuration by registering options, merging them with settings files, and applying precedence rules where configuration files override CLI arguments.

The avocado-framework/avocado-vt repository provides the Virt Test (VT) plugin for Avocado, enabling automated virtualization testing across QEMU, libvirt, and other backends. At the heart of this system lies the VirtTestOptionsProcess class defined in avocado_vt/options.py, which serves as the bridge between user-supplied command-line arguments and the internal cartesian test matrix used by the virt-test framework.

The Three-Stage Processing Pipeline

The VirtTestOptionsProcess operates through a deterministic three-stage pipeline that transforms raw CLI input into a structured test configuration.

Stage 1: Option Registration in the VT Plugin

Before any parsing occurs, the VT plugin registers all VT-specific flags with Avocado's argument parser. In avocado_vt/plugins/vt.py, the functions add_basic_vt_options and add_qemu_bin_vt_option attach flags such as --vt-type, --vt-arch, --vt-guest-os, and --vt-qemu-bin to the run sub-parser.

Each registration maps the CLI flag to a configuration key under the vt.* namespace. For example, --vt-type qemu populates config['vt.type'] = 'qemu'. The QEMU binary option includes auto-detection logic that defaults to the system QEMU installation if no explicit path is provided.

Stage 2: Configuration Loading and Merging

When avocado run executes, the VirtTestOptionsProcess initializes with a Config object containing values from multiple sources. The __init__ method in avocado_vt/options.py (lines 43-66) orchestrates this merge:

  1. CLI arguments override any defaults
  2. Settings files (conf.d/*.conf) are loaded via set_opt_from_settings, copying vt.* entries into the Config object
  3. Built-in defaults apply when neither CLI nor settings provide a value

This layered approach ensures that environment-specific defaults can persist in configuration files while allowing one-off CLI overrides for ad-hoc test runs.

Stage 3: Cartesian Parser Translation

The final stage converts the merged configuration into a cartesian test matrix. The _process_options method creates a fresh cartesian_config.Parser instance and delegates to specialized private methods for each option family:

  • _process_qemu_bin handles --vt-qemu-bin and auto-discovery via standalone_test.find_default_qemu_paths
  • _process_bridge_mode validates nettype against SUPPORTED_NET_TYPES and applies bridge or user networking defaults based on UID
  • _process_monitor configures QEMU monitor settings
  • _process_smp translates CPU count into cartesian filters

Each helper follows strict precedence rules: if vt.config (a configuration file) is specified, most CLI options are ignored with a logged message, as the config file is considered authoritative. Otherwise, the explicit CLI value or settings file value is assigned to the cartesian parser using assign, only_filter, or no_filter calls.

Key Processing Methods and Precedence Rules

Understanding the internal methods of VirtTestOptionsProcess reveals how the system handles edge cases and conflicting inputs.

Configuration File vs. Command-Line Precedence

The _process_* methods consistently implement a precedence hierarchy:

  1. Configuration file (--vt-config) takes absolute precedence. When present, the method logs LOG.info("Config provided, ignoring %s", option_name) and skips CLI processing for that option.
  2. Explicit CLI flags override settings file values when no config file is used.
  3. Settings files (conf.d/*.conf) provide defaults when neither CLI nor config file specifies a value.
  4. Hardcoded defaults apply as final fallbacks.

This hierarchy ensures reproducible test runs: a configuration file captures the complete environment state, while CLI flags allow quick iterations during development.

Backend-Specific Processing

The _process_backend_specific_options method dispatches to specialized handlers based on vt.type:

  • QEMU: Invokes _process_qemu_bin, _process_smp, and other QEMU-specific routines defined in options.py
  • LVSB (Linux Virtual Server Base): Uses a simplified processing path that skips general options
  • libvirt: Applies libvirt-specific configuration mappings
  • spice: Handles SPICE protocol-specific settings

Each backend can inject its own defaults. For example, QEMU processing automatically detects binary paths via virttest/standalone_test.py's find_default_qemu_paths function when the user does not specify --vt-qemu-bin and no config file is present.

Practical Examples

Running a VT Test from the Command Line


# Basic QEMU test on x86_64 with a custom QEMU binary

avocado run my_test.py \
    --vt-type qemu \
    --vt-arch x86_64 \
    --vt-qemu-bin /usr/local/bin/qemu-system-x86_64 \
    --vt-smp 4 \
    --vt-no-filter "no_9p_export"

Explanation:

  • --vt-type selects the backend (qemu).
  • --vt-arch forces the cartesian parser to filter on the x86_64 architecture.
  • --vt-qemu-bin overrides the auto-detected binary; the path is stored in the cartesian parser as qemu_binary.
  • --vt-smp 4 triggers _process_smp, which adds the smp2 filter for the default case and, because the value is not 1 or 2, it assigns smp = 4.
  • --vt-no-filter removes the no_9p_export filter from the default test matrix.

Using a Configuration File (Overrides CLI Flags)

my_vt.cfg (placed in the current directory or pointed by --vt-config):

vt.type = qemu
vt.common.arch = aarch64
vt.qemu.qemu_bin = /opt/qemu/bin/qemu-system-aarch64
vt.qemu.smp = 2

Run:

avocado run my_test.py --vt-config my_vt.cfg --vt-arch x86_64

Result: The --vt-arch flag is ignored because a config file is present; the parser uses aarch64 from the file. This is logged by the _process_arch routine (LOG.info("Config provided, ignoring %s", arch_setting)).

Programmatic Use (Python)

from avocado.core import config
from avocado_vt.options import VirtTestOptionsProcess

# Build an Avocado config manually

cfg = config.Config()
cfg['vt.type'] = 'qemu'
cfg['vt.qemu.smp'] = '4'   # emulate a 4-CPU VM

cfg['vt.common.nettype'] = 'bridge'

opts = VirtTestOptionsProcess(cfg)
parser = opts.get_parser()          # ← fully resolved cartesian parser

print(parser._cartesian)            # internal representation

The Python snippet shows how the same option-processing logic can be reused by other tools that need to generate the cartesian matrix without invoking the CLI.

Summary

  • VirtTestOptionsProcess in avocado_vt/options.py serves as the central translator between VT CLI flags and the cartesian test matrix.
  • The workflow follows three stages: option registration in avocado_vt/plugins/vt.py, configuration merging during initialization, and cartesian parser population via specialized _process_* methods.
  • Precedence rules strictly favor configuration files (--vt-config) over CLI flags, with settings files and hardcoded defaults as fallbacks.
  • Backend-specific handlers dispatch processing based on vt.type, enabling tailored logic for QEMU, libvirt, LVSB, and SPICE test environments.
  • The system supports both CLI invocation and programmatic reuse via direct Python instantiation of VirtTestOptionsProcess.

Frequently Asked Questions

What happens when both --vt-config and --vt-type are specified?

When a configuration file is provided via --vt-config, the vt.type value from that file takes precedence over the --vt-type CLI flag. The _process_general_options method checks for the presence of vt.config and logs that CLI flags are being ignored, ensuring the configuration file serves as the authoritative source for test parameters.

How does VirtTestOptionsProcess determine the default QEMU binary?

If no --vt-qemu-bin flag is provided and no configuration file is specified, the _process_qemu_bin method calls find_default_qemu_paths from virttest/standalone_test.py. This helper searches standard system paths for qemu-system-* binaries and related tools (qemu-img, qemu-io), returning the discovered paths to be assigned to the cartesian parser as qemu_binary, qemu_img_binary, and qemu_io_binary.

Can I use VirtTestOptionsProcess programmatically without the Avocado CLI?

Yes, you can instantiate VirtTestOptionsProcess directly with a manually constructed Config object. Import the class from avocado_vt.options, populate a configuration dictionary with keys like vt.type, vt.qemu.smp, and vt.common.nettype, then call get_parser() to receive a fully resolved cartesian parser. This enables custom tools to generate test matrices without invoking the avocado run command.

What is the precedence order for VT configuration values?

The VirtTestOptionsProcess applies a strict four-level hierarchy: Configuration file (--vt-config) overrides all other sources; Explicit CLI flags (e.g., --vt-arch) override settings files and defaults when no config file is used; Settings files (conf.d/*.conf) provide defaults when neither CLI nor config file specifies a value; Hardcoded defaults apply as final fallbacks. This precedence is enforced consistently across all _process_* methods in options.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →