# cloudinit-vm: one cloud-init-provisioned VM booting from a shared base
# image via copy-on-write. For Office1's own service VMs (MAAS-region,
# NetBox, GitBucket -- D-103) -- genuinely different from
# modules/node-vm's blank-disk PXE pattern, which is for MAAS-managed
# OpenStack nodes that MAAS itself images after enlistment. Call
# modules/base-image once per distinct image, this module once per VM
# instance.
#
# NOT CONFIRMED for OPNsense: this whole pattern (cloud-init/NoCloud via
# libvirt_cloudinit_disk) is standard for Linux cloud images; OPNsense is
# FreeBSD-based and its cloud-init/NoCloud support is not the same guarantee.
# Do not assume this module covers OPNsense without checking that
# specifically first -- see opentofu/README.md.
#
# Every resource/attribute shape below is used exactly as shown in
# examples/alpine_cloudinit.tf (fetched and read directly this session, tag
# v0.9.8) -- attribute-style nested objects throughout, same convention as
# modules/node-vm and the corrected modules/dc-planes etc. No `graphics`
# block: this is a headless server VM pattern (the real example included VNC
# graphics; omitted here as unnecessary for a service VM, not because it's
# confirmed invalid to include -- add it back if console-debug access is
# ever wanted).
resource "libvirt_volume" "disk" {
name = "${var.vm_name}-disk.qcow2"
pool = var.pool_name
capacity = var.disk_size_bytes
target = {
format = {
type = "qcow2"
}
}
backing_store = {
path = var.base_volume_path # the caller passes module.<base_image>.path
# straight through -- a real attribute
# reference, matching
# examples/alpine_cloudinit.tf's
# `libvirt_volume.alpine_base.path` exactly,
# just threaded across a module boundary
# instead of within one file.
format = {
type = "qcow2"
}
}
}
resource "libvirt_cloudinit_disk" "seed" {
name = "${var.vm_name}-cloudinit"
user_data = var.user_data
meta_data = var.meta_data
network_config = var.network_config
}
resource "libvirt_volume" "seed" {
name = "${var.vm_name}-cloudinit.iso"
pool = var.pool_name
create = {
content = {
url = libvirt_cloudinit_disk.seed.path
}
}
}
resource "libvirt_domain" "vm" {
name = var.vm_name
memory = var.memory_mib
vcpu = var.vcpu
type = "kvm"
running = true
os = {
type = "hvm"
type_arch = "x86_64"
type_machine = "q35"
}
devices = {
disks = [
{
source = {
volume = {
pool = libvirt_volume.disk.pool
volume = libvirt_volume.disk.name
}
}
target = {
dev = "vda"
bus = "virtio"
}
driver = {
type = "qcow2"
}
},
{
device = "cdrom"
source = {
volume = {
pool = libvirt_volume.seed.pool
volume = libvirt_volume.seed.name
}
}
target = {
dev = "sda"
bus = "sata"
}
}
]
interfaces = [
for net_name in var.network_names : {
model = {
type = "virtio"
}
source = {
network = {
network = net_name
}
}
}
]
}
}