Skip to content

Examples don't reflect updated schema #1243

@hpst3r

Description

@hpst3r

Problem

Hi there,

A lot of the devices in the examples (or, at least, the Alpine example - I haven't had time to look into the others yet) are invalid with v0.9.1 since they don't yet reflect the updated schema.

For example, in the alpine_cloudinit.tf sample, the disks are missing a nested volume object, the format parameters for disks are incorrect (the old syntax), and a lot of the devices are missing new nested objects or parameters, so the example fails to validate or apply.

I prepared a PR to update the Alpine example so it:

There's also a discrepancy with the format parameters in the backing_store and libvirt_volume itself, but I'm not sure if this is actually a problem.

Unsure if this affects other examples but I expect it does. Documentation is also affected.

env

My client machine is running Terraform 1.14, provider 0.9.1 on amd64 Linux, and the provider target is Alma (Rocky/RHEL) 10.1 with libvirt 11.5.0 (11.5.0-4.1.el10_1.alma.1).

Troubleshooting

Disk format

If this devices = { disks = [ { source = {} } ] } syntax is used, Terraform applies fail. The provider now expects a nested volume object (under source).

To reproduce from the example, I pulled down the Alpine example and changed only the provider to:

provider "libvirt" {
  uri = "qemu+sshcmd://[email protected]/system"
}

First, Terraform fails to apply thanks to the format parameter:

$ terraform apply
╷
│ Error: Unsupported argument
│ 
│   on main.tf line 17, in resource "libvirt_volume" "alpine_base":
│   17:   format = "qcow2"
│ 
│ An argument named "format" is not expected here.
╵

Disk error is caused by this snippet (same case for both vda and the cdrom):

devices = {
  disks = [
    { # root disk
      source = {
        pool = libvirt_volume.terraform-errata-root-disk.pool
        volume = libvirt_volume.terraform-errata-root-disk.name
      }
    }
  ]
}

Pointing source at a volume object works:

devices = {
  disks = [
    { # root disk
      source = {
        volume = {
          pool = libvirt_volume.terraform-errata-root-disk.pool
          volume = libvirt_volume.terraform-errata-root-disk.name
        }
      }
    }
  ]
}

Relevant excerpt from the original example (nonfunctional):

devices = {
  disks = [
    {
      source = {
        pool   = libvirt_volume.alpine_disk.pool
        volume = libvirt_volume.alpine_disk.name
      }
      target = {
        dev = "vda"
        bus = "virtio"
      }
    },
    {
      device = "cdrom"
      source = {
        pool   = libvirt_volume.alpine_seed_volume.pool
        volume = libvirt_volume.alpine_seed_volume.name
      }
      target = {
        dev = "sda"
        bus = "sata"
      }
    }
  ]
}

Device changes

After replacing format = "qcow2" with the new target = { format = { type = "qcow2" } }:

$ terraform apply
╷
│ Error: Missing required argument
│ 
│   on main.tf line 95, in resource "libvirt_domain" "alpine":
│   95: resource "libvirt_domain" "alpine" {
│ 
│ The argument "type" is required, but no definition was found.
╵
╷
│ Error: Incorrect attribute value type
│ 
│   on main.tf line 106, in resource "libvirt_domain" "alpine":
│  106:   devices = {
│  107:     disks = [
│  108:       {
│  109:         source = {
│  110:           volume = {
│  111:             pool   = libvirt_volume.alpine_disk.pool
│  112:             volume = libvirt_volume.alpine_disk.name
│  113:           }
│  114:         }
│  115:         target = {
│  116:           dev = "vda"
│  117:           bus = "virtio"
│  118:         }
│  119:       },
│  120:       {
│  121:         device = "cdrom"
│  122:         source = {
│  123:           volume = {
│  124:             pool   = libvirt_volume.alpine_seed_volume.pool
│  125:             volume = libvirt_volume.alpine_seed_volume.name
│  126:           }
│  127:         }
│  128:         target = {
│  129:           dev = "sda"
│  130:           bus = "sata"
│  131:         }
│  132:       }
│  133:     ]
│  134:     interfaces = [
│  135:       {
│  136:         type  = "network"
│  137:         model = "virtio"
│  138:         source = {
│  139:           network = "default"
│  140:         }
│  141:       }
│  142:     ]
│  143:     graphics = {
│  144:       vnc = {
│  145:         autoport = "yes"
│  146:         listen   = "127.0.0.1"
│  147:       }
│  148:     }
│  149:   }
│ 
│ Inappropriate value for attribute "devices": attribute "interfaces": element 0: attribute "source":
│ attribute "network": object required, but have string.
╵

After adding the type = "kvm" argument to the libvirt_domain definition and modifying the interfaces = [ { model, source } ] definitions from:

interfaces = [
  {
    type  = "network"
    model = "virtio"
    source = {
      network = "default"
    }
  }
]

To:

interfaces = [
  {
    type  = "network"
    model = { type = "virtio" }
    source = {
      network = {
        network = "default"
      }
    }
  }
]

I receive:

$ terraform apply
│ Inappropriate value for attribute "devices": attribute "graphics": list of object required.

After changing:

graphics = {
  vnc = {
    autoport = "yes"
    listen   = "127.0.0.1"
  }
}

To:

graphics = [
  {
    type = "vnc"
    vnc = {
      autoport = true
      listen   = "127.0.0.1"
    }
  }
]

Terraform successfully creates all the objects. However, the VM still doesn't boot; it can't read its boot device.

I found this is because, when the backing_store for a volume is defined as:

backing_store = {
  path = libvirt_volume.alpine_base.path
  source = {
    format = {
      type = "qcow2"
    }
  }
}

The format parameter doesn't behave the same way as it does for a normal libvirt_volume.

Generated XML in the above case. Note the format type='raw'.

<disk type='volume' device='disk'>
  <driver name='qemu' type='qcow2'/>
  <source pool='default' volume='alpine-vm.qcow2' index='2'/>
  <backingStore type='file' index='3'>
    <format type='raw'/>
    <source file='/var/lib/libvirt/images/alpine-3.22-base.qcow2'/>
    <backingStore/>
  </backingStore>
  <target dev='vda' bus='virtio'/>
  <alias name='virtio-disk0'/>
  <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
</disk>

The backing_store works only if the source is removed (format is nested under just backing_store, not backing_store = { source = {} }:

backing_store = {
  path   = libvirt_volume.alpine_base.path
  format = {
      type = "qcow2"
  }
}

This is an example of the full XML for the disk (when working):

<disk type='volume' device='disk'>
  <driver name='qemu' type='qcow2'/>
  <source pool='default' volume='alpine-vm.qcow2' index='2'/>
  <backingStore type='file' index='3'>
    <format type='qcow2'/>
    <source file='/var/lib/libvirt/images/alpine-3.22-base.qcow2'/>
    <backingStore/>
  </backingStore>
  <target dev='vda' bus='virtio'/>
  <alias name='virtio-disk0'/>
  <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
</disk>

Seems a little odd to me that the format.type is nested under target in the provider, but I'm not sure if that's from the backing API or not.

Testing

Anyway, with all these changes, the VM now boots:

Image

I will submit a PR shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions