Skip to content

MonolithProjects/terraform-libvirt-vm

Repository files navigation

Libvirt VM Terraform module

GitHub Actions License Terraform

Terraform module for KVM/Libvirt Virtual Machine. This module will create a KVM Virtual Machine(s), configure it using Cloud Init and test the ssh connection. This module is using dmacvicar/libvirt Terraform provider.

What it provides

  • creates one or more VMs
  • one NIC per domain, connected to the network using the bridge interface
  • setup network interface using DHCP or static configuration
  • cloud_init VM(s) configuration (Ubuntu+Netplan complient)
  • optionally add multiple extra disks
  • test the ssh connection

Tested on

  • Ubuntu 20.04 TLS Cloud Image
  • Ubuntu 22.04 TLS Cloud Image

Requirements

Name Version
terraform >= 1.0
libvirt >= 0.7.0

Modules

No modules.

Resources

Name Type
libvirt_cloudinit_disk.commoninit resource
libvirt_domain.virt-machine resource
libvirt_volume.base-volume-qcow2 resource
libvirt_volume.volume-qcow2 resource

Inputs

Name Description Type Default Required
additional_disk_ids List of volume ids list(string) [] no
autostart Autostart the domain bool true no
base_pool_name Name of base OS image string null no
base_volume_name Name of base OS image string null no
bridge Bridge interface string "virbr0" no
cpu_mode CPU mode string "host-passthrough" no
dhcp Use DHCP or Static IP settings bool false no
graphics Graphics type (can be 'spice' or 'vnc') string spice no
index_start From where the indexig start number 1 no
ip_address List of IP addresses list(string)
[
"192.168.123.101"
]
no
ip_gateway IP addresses of a gateway string "192.168.123.1" no
ip_nameserver IP addresses of a nameserver string "192.168.123.1" no
local_admin Admin user without ssh access string "" no
local_admin_passwd Local admin user password string "password_example" no
memory RAM in MB string "1024" no
os_img_url URL to the OS image string "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" no
pool Storage pool name string "default" no
runcmd Extra commands to be run with cloud init list(string)
[
"[ systemctl, daemon-reload ]",
"[ systemctl, enable, qemu-guest-agent ]",
"[ systemctl, start, qemu-guest-agent ]",
"[ systemctl, restart, systemd-networkd ]"
]
no
share_filesystem n/a
object({
source = string
target = string
readonly = bool
mode = string
})
{
"mode": null,
"readonly": false,
"source": null,
"target": null
}
no
ssh_admin Admin user with ssh access string "ssh-admin" no
ssh_keys List of public ssh keys list(string) [] no
ssh_private_key Private key for SSH connection test (either path to file or key content) string null no
system_volume System Volume size (GB) number 10 no
time_zone Time Zone string "UTC" no
vcpu Number of vCPUs number 1 no
vm_count Number of VMs number 1 no
vm_hostname_prefix VM hostname prefix string "vm" no
xml_override With these variables you can: Enable hugepages; Set USB controllers; Attach USB devices
object({
hugepages = bool
usb_controllers = list(object({
model = string
}))
usb_devices = list(object({
vendor = string
product = string
}))
pci_devices_passthrough = list(object({
src_domain = string
src_bus = string
src_slot = string
src_func = string
dst_domain = string
dst_bus = string
dst_slot = string
dst_func = string
}))
})
{
"hugepages": false,
"usb_controllers": [
{
"model": "piix3-uhci"
}
],
"usb_devices": []
"pci_devices_passthrough": []
}
no
bastion_host ssh bastion host string null no
bastion_user ssh user on bastion host string null no
bastion_ssh_private_key ssh private key for bastion host (either path to file or key content) string null no

Outputs

Name Description
ip_address n/a
name n/a

Example

Example with enable HugePages, Attached USB device, changed USB controller model... :

terraform { required_version = ">= 0.13" required_providers { libvirt = { source = "dmacvicar/libvirt" } } } resource "tls_private_key" "ecdsa-p384-bastion" { algorithm = "ECDSA" ecdsa_curve = "P384" } provider "libvirt" { uri = "qemu+ssh://hero@192.168.165.100/system" } module "vm" { source = "MonolithProjects/vm/libvirt" version = "1.8.0" vm_hostname_prefix = "server" vm_count = 3 memory = "2048" vcpu = 1 pool = "terra_pool" system_volume = 20 dhcp = true local_admin = "local-admin" ssh_admin = "ci-user" ssh_private_key = "~/.ssh/id_ed25519" local_admin_passwd = "$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD" ssh_keys = [ "ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example", ] bastion_host = "10.0.0.1" bastion_user = "admin" bastion_ssh_private_key = tls_private_key.ecdsa-p384-bastion.private_key_pem time_zone = "CET" os_img_url = "file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img" xml_override = { hugepages = true, usb_controllers = [ { model = "qemu-xhci" } ], usb_devices = [ { vendor = "0x0bc2", product = "0xab28" } ] pci_devices_passthrough = [ { src_domain = "0x0000", src_bus = "0xc1", src_slot = "0x00", src_func = "0x0", dst_domain = "0x0000", dst_bus = "0x00", dst_slot = "0x08" dst_func = "0x0" }, { src_domain = "0x0000", src_bus = "0xc1", src_slot = "0x00", src_func = "0x1", dst_domain = "0x0000", dst_bus = "0x00", dst_slot = "0x09" dst_func = "0x0" } ] } } output "ip_addresses" { value = module.nodes }

Static IP settings... :

terraform { required_version = ">= 0.13" required_providers { libvirt = { source = "dmacvicar/libvirt" version = "0.6.3" } } } provider "libvirt" { uri = "qemu+ssh://hero@192.168.165.100/system" } module "vm" { source = "MonolithProjects/vm/libvirt" version = "1.8.0" vm_hostname_prefix = "server" vm_count = 3 memory = "2048" vcpu = 1 pool = "terra_pool" system_volume = 20 share_filesystem = { source = "/tmp" target = "tmp" readonly = false } dhcp = false ip_address = [ "192.168.165.151", "192.168.165.152", "192.168.165.153" ] ip_gateway = "192.168.165.254" ip_nameserver = "192.168.165.104" local_admin = "local-admin" ssh_admin = "ci-user" ssh_private_key = "~/.ssh/id_ed25519" local_admin_passwd = "$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD" ssh_keys = [ "ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example", ] time_zone = "CET" os_img_url = "file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img" } output "outputs" { value = module.nodes }

The shared directory from the example can be mounted inside the VM with command sudo mount -t 9p -o trans=virtio,version=9p2000.L,rw tmp /host/tmp

Create a VM with an extra disk

# Creates a 50GB extra-data-disk within vms pool resource "libvirt_volume" "data_volume" { pool = "vms" name = "extra-data-disk.qcow2" format = "qcow2" size = 1024*1024*1024*50 } module "vm" { source = "MonolithProjects/vm/libvirt" version = "1.8.0" vm_hostname_prefix = "data-server" base_volume_name = "debian-11-base.qcow2" base_pool_name = "linked-images" vm_count = 1 bridge = "bridge-dmz" memory = "4096" vcpu = 4 pool = "vms" system_volume = 25 additional_disk_ids = [ libvirt_volume.data_volume.id ] dhcp = true ssh_admin = "admin" ssh_keys = [ chomp(file("~/.ssh/id_rsa.pub")) ] time_zone = "America/Argentina/Buenos_Aires" } output "ip_addresses" { value = module.vm } 

Module output example

output_data = { "ip_address" = [ "192.168.165.151", "192.168.165.152", "192.168.165.153", ] "name" = [ "server01", "server02", "server03", ] }

License

MIT

Author Information

Created in 2020 by Michal Muransky

Packages

No packages published

Contributors 6