terraform-provider-libvirt

repository·main·Indexed 23 days ago

https://github.com/dmacvicar/terraform-provider-libvirt

A Terraform provider for managing libvirt virtualization resources, including virtual machines (domains), storage pools, networks, and volumes. It provides high API fidelity by mirroring libvirt XML schemas directly and includes data sources for retrieving domain IP addresses and node device information.

Tokens
81.2K
Snippets
87
Records
357
Agent score
81%

What's inside terraform-provider-libvirt

  1. Configure disk mirroring backing store sources in libvirt_domain

    main

    When configuring disk mirroring within a libvirt_domain resource, you must specify a source for the backing_store. This source defines where the data for the mirror is located. The source block is a polymorphic configuration that accepts different types of storage backends.

    Common source types include:

    • block: For physical block devices (requires dev).
    • file: For local files (requires file).
    • dir: For directory-based storage (requires dir).
    • data_store: For data store formats (requires type and format).
    • network: For network-based storage.
    • volume: For storage volumes.
    • vhost_user or vhost_vdpa: For specialized high-performance interfaces.
  2. Understand how libvirt XML maps to Terraform HCL

    main

    The terraform-provider-libvirt maps libvirt XML structures to Terraform HCL using specific transformation rules. Understanding these rules helps you predict how to configure resources.

    Core Mapping Rules

    • Nesting: XML elements are mapped to nested attributes (schema.SingleNestedAttribute or schema.ListNestedAttribute). The provider avoids using Terraform blocks for new features.
    • Lists: Repeated XML elements are represented as lists of nested objects. The order of elements is preserved.
    • Attributes: XML attributes are kept as scalar values within their containing object.
    • Naming: Names are converted to snake_case. Common acronyms like mac_address, uuid, and nvram remain unchanged.
    • Field Population:
      • Optional fields: Only populated on reads if the user explicitly set them.
      • Computed fields: Always populated on reads.
      • Required fields: Always populated.

    Common Transformation Patterns

    • Containers: XML containers become nested objects holding their children (e.g., <devices> becomes devices = { disks = [...], interfaces = [...] }).
    • Value + Unit Flattening: If an element has a value and a single extra attribute (like a unit), they are flattened into two top-level attributes. For example, <memory unit="MiB">512</memory> becomes memory = 512 and memory_unit = "MiB".
    • Complex Flattening: If an element has two or more extra attributes, it is mapped to a nested object (e.g., vcpu = { value = 4, placement = "static", cpuset = "0-3" }).
    • Presence-only elements: Elements like <acpi/> map to booleans. Setting the attribute to true emits the element; false or null omits it.
    • Union/Variant Branches: For elements where only one branch can be set, use a nested object where only one branch is populated (e.g., source = { file = "..." } or source = { volume = { ... } }).
    • Booleans: XML yes/no attributes are converted to booleans.
    • Implicit Types: In cases where the XML type is implied by the chosen branch (like interfaces), the type attribute is omitted in HCL.
  3. How to choose between qemu+ssh:// and qemu+sshcmd://

    main

    The provider offers two SSH transport options depending on your requirements:

    qemu+ssh:// (Go SSH Library)

    Use this if:

    • You want a pure Go solution without external dependencies.
    • You have simple, straightforward SSH authentication.
    • You need maximum portability.

    Note: It does not respect ~/.ssh/config and lacks support for ProxyJump.

    qemu+sshcmd:// (Native SSH Command)

    Use this if:

    • You have complex SSH configurations (bastion hosts, proxy jumps).
    • You need to respect existing SSH config files.
    • You use SSH agent forwarding or advanced SSH features.

    Note: Requires the ssh binary to be installed and nc (netcat) or virt-ssh-helper on the remote system.

  4. Use Provider Lifecycle Blocks for operation control

    main

    Some resources allow you to control provider-level operations via nested create and destroy attributes. These attributes control API calls related to the resource lifecycle (such as build, start, or delete operations) rather than modifying the XML configuration itself.

    Note: Lifecycle operation controls are considered experimental and may change between provider releases. They follow the standard nested-attribute style:

    • create = { ... }
    • destroy = { ... }
  5. Use lifecycle operation controls for resources

    main

    Some resources allow controlling post-define and pre-undefine API operations (like build, start, or delete behavior) via nested create and destroy objects. These are provider-specific controls and are not direct libvirt XML fields. Note that these controls are currently experimental.

    Example for libvirt_pool:

    resource "libvirt_pool" "data" {
      name = "data-pool"
      type = "dir"
      target = {
        path = "/var/lib/libvirt/data"
      }
    
      create = {
        build     = true
        start     = true
        autostart = true
      }
    
      destroy = {
        delete = false
      }
    }
  6. How the Code Generator works

    main

    The generator uses a multi-stage pipeline to transform libvirtxml reflection and documentation into Terraform provider code:

    1. Inputs: It consumes libvirtxml reflection data and a documentation registry (YAML files located in internal/codegen/docs/).
    2. IR Builder: Normalizes struct metadata, tracks optionality, and carries docstrings into an Intermediate Representation (IR).
    3. Field Policy Layer: Applies Terraform-specific semantics (like Computed, Required, or RequiresReplace) to the reflected fields.
    4. Generators: Templates render the IR into Go files (models, schemas, and converters) located in internal/generated/*.gen.go.
    5. Orchestration: The main.go entry point manages the workflow and runs gofmt on the output.
  7. Configure libvirt_domain features

    main

    The libvirt_domain resource allows you to configure various virtualization features for a guest VM. These features are grouped under the features attribute and include support for interrupt controllers, security capabilities, and hypervisor-specific optimizations.

    Key feature groups include:

    • Interrupt Handling: aia (Advanced Interrupt Affinity), apic (Advanced Programmable Interrupt Controller), gic (Generic Interrupt Controller), and ioapic.
    • Hypervisor Specifics: hyper_v (Hyper-V features), kvm (KVM features), xen (Xen features), and viridian (Windows virtualization).
    • Security & Capabilities: capabilities (defines security policies and granular permissions), smm (Secure Memory Management), and tcg (Trusted Computing Group).
    • Performance & Hardware: async_teardown (asynchronous shutdown), pae (Physical Address Extension), pmu (Performance Monitoring Unit), and msrs (Model Specific Registers).
  8. Preserve User Intent for Optional Nested Objects

    main

    The generator follows a strict contract for optional nested objects to prevent Terraform Provider produced inconsistent result after apply errors. This is critical for fields like alias, where libvirt might not round-trip the XML exactly as provided.

    When converting XML back to a model, the generator distinguishes between three states:

    1. Plan field is null: The user did not configure the object; the state remains null.
    2. Plan field is non-null AND XML field is present: The XML is converted back into the state.
    3. Plan field is non-null AND XML field is absent: The generator preserves the planned value instead of collapsing it to null. This ensures that if a user explicitly configures an object that libvirt happens to omit during readback, Terraform doesn't try to delete it.
  9. Configure NV RAM source types for libvirt_domain

    main

    The os.nv_ram.source block in the libvirt_domain resource allows you to specify various backend types for non-volatile RAM (NV RAM) reservations. Depending on your requirements, you can use one of the following source types:

    • file: Uses a file path as the source. Requires path. Supports append and sec_label.
    • nmdm: Uses a master-slave NMDM configuration. Requires master and slave device paths.
    • pipe: Uses a named pipe. Requires path. Supports sec_label.
    • pty: Uses a Pseudo TTY device. Requires path. Supports sec_label.
    • qemuvd_agent: Uses the QEMU guest agent. Supports clip_board (requires copy_paste) and mouse (requires mode).
    • spice_port: Uses a SPICE port. Requires channel.
    • tcp: Uses a TCP connection. Supports host, mode, service, tls, and reconnect settings.
    • udp: Uses a UDP connection. Requires bind_host, bind_service, connect_host, and connect_service.
    • unix: Uses a UNIX domain socket. Supports path, mode, reconnect, and sec_label.
    • ssl: Uses an SSL connection. Requires verify level.
    • slices: Uses individual slice configurations (mirror source). Supports a list of slices with offset, size, and type.
  10. Configure smartcard passthrough sources

    main

    When using devices.smartcards.passthrough, you must specify one of the following source types to define how the smartcard backend connects:

    • dev: Uses a device file. Requires path (String) and optional sec_label.
    • file: Uses a file source. Requires path (String) and optional append and sec_label.
    • nmdm: Uses a null modem device. Requires master (String) and slave (String).
    • pipe: Uses a pipe. Requires path (String) and optional sec_label.
    • pty: Uses a pseudo-terminal. Requires path (String) and optional sec_label.
    • dbus: Uses a DBus source. Requires channel (String).
    • null: Configures a null source.

    Other available backend settings include qemuvd_agent, spice_port, spice_vmc, std_io, tcp, udp, unix, and vc (virtual console connection).