Skip to content

Instantly share code, notes, and snippets.

@bvierra
Last active March 15, 2024 15:24
Show Gist options
  • Save bvierra/55f1aa4ac225aa83176e8c424165ae1f to your computer and use it in GitHub Desktop.
Save bvierra/55f1aa4ac225aa83176e8c424165ae1f to your computer and use it in GitHub Desktop.
proxmox qemu vm module w/cloud-init
# use Telmate/proxmox 3.0.1-rc1 provider
terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "3.0.1-rc1"
}
}
}
# Load the file from var.vm_ssh_private_key_path and var.vm_ssh_public_key_path as local sensitive files to keep the contents from being displayed in the plan output
data "local_sensitive_file" "ssh_private_key" {
filename = var.vm_ssh_private_key_path
}
data "local_sensitive_file" "ssh_public_key" {
filename = var.vm_ssh_public_key_path
}
# Create the cloud-init file from template and store into the generated folder
resource "local_sensitive_file" "cloud_init" {
content = templatefile(local.template_ci_userdata_filename, {
hostname = var.vm_name,
fqdn = "${var.vm_name}.${var.vm_domain_name}",
ansible_user = var.ansible_user,
ansible_password = var.ansible_password,
ansible_public_key = data.local_sensitive_file.ssh_public_key.content,
serial_added = local.serial_added
})
filename = "${var.generated_folder}/cloud-init/${var.project_name}-${var.vm_name}-cloud_init.yml"
file_permission = "0644"
}
# Transfer the cloud-init file from the generated folder to the Proxmox server
# This only triggers if the sha1 from the cloud_init creation changes
resource "null_resource" "cloud_init" {
connection {
type = "ssh"
user = var.vm_proxmox_ssh_user
private_key = file(var.vm_proxmox_ssh_private_key_path)
host = var.vm_proxmox_ssh_server
}
provisioner "file" {
source = local_sensitive_file.cloud_init.filename
destination = "/mnt/pve/${var.vm_proxmox_snippets_storage_pool}/snippets/${var.project_name}-${var.vm_name}-cloud_init.yml"
}
triggers = {
cloud_init_sh1 = resource.local_sensitive_file.cloud_init.content_sha1
}
}
resource "proxmox_vm_qemu" "vm" {
depends_on = [
null_resource.cloud_init
]
name = var.vm_name
target_node = var.vm_target_node
clone = var.vm_clone
full_clone = var.vm_full_clone
hastate = var.vm_hastate
hagroup = var.vm_hagroup
agent = var.vm_agent
desc = var.vm_description
qemu_os = var.vm_qemu_os
balloon = var.vm_memory_minimum
memory = var.vm_memory_maximum
numa = var.vm_numa
sockets = var.vm_sockets
cores = var.vm_cores
cpu = var.vm_cpu
hotplug = var.vm_hotplug
scsihw = var.vm_scsi_controller
pool = var.vm_pool
disks {
virtio {
virtio0 {
disk {
storage = var.vm_disk_storage
size = var.vm_disk_size
format = var.vm_disk_format
iothread = var.vm_scsi_controller == "virtio-scsi-single" ? true : false
cache = var.vm_disk_cache
}
}
}
}
serial {
id = var.vm_serial_id
type = var.vm_serial_type
}
os_type = "cloud-init"
nameserver = var.vm_nameserver
cicustom = "user=${var.vm_proxmox_snippets_storage_pool}:snippets/${var.project_name}-${var.vm_name}-cloud_init.yml"
cloudinit_cdrom_storage = var.vm_cloudinit_cdrom_storage
ipconfig0 = length(var.vm_ipconfig) >= 1 ? var.vm_ipconfig[0] : null
ipconfig1 = length(var.vm_ipconfig) >= 2 ? var.vm_ipconfig[1] : null
ipconfig2 = length(var.vm_ipconfig) >= 3 ? var.vm_ipconfig[2] : null
ipconfig3 = length(var.vm_ipconfig) >= 4 ? var.vm_ipconfig[3] : null
ipconfig4 = length(var.vm_ipconfig) >= 5 ? var.vm_ipconfig[4] : null
ipconfig5 = length(var.vm_ipconfig) >= 6 ? var.vm_ipconfig[5] : null
ipconfig6 = length(var.vm_ipconfig) >= 7 ? var.vm_ipconfig[6] : null
ipconfig7 = length(var.vm_ipconfig) >= 8 ? var.vm_ipconfig[7] : null
ipconfig8 = length(var.vm_ipconfig) >= 9 ? var.vm_ipconfig[8] : null
dynamic "network" {
for_each = var.vm_networks
iterator = network
content {
model = network.value["model"]
bridge = network.value["bridge"]
tag = network.value["tag"]
firewall = network.value["firewall"]
link_down = network.value["link_down"]
}
}
force_recreate_on_change_of = resource.local_sensitive_file.cloud_init.content_sha1
tags = var.vm_tags
}
output "ssh_host" {
value = proxmox_vm_qemu.vm.ssh_host
}
output "name" {
value = proxmox_vm_qemu.vm.name
}
#cloud-config
preserve_hostname: false
hostname: ${hostname}
fqdn: ${fqdn}
prefer_fqdn_over_hostname: true
manage_etc_hosts: true
package_update: true
package_upgrade: true
packages:
- vim
- tmux
- git
- curl
- wget
- sudo
- ansible
%{ if serial_added ~}
runcmd:
- [ systemctl, enable, [email protected] ]
- [ systemctl, start, --no-block, [email protected] ]
%{ endif ~}
users:
- name: ${ansible_user}
passwd: ${ansible_password}
ssh-authorized-keys:
- ${ansible_public_key}
sudo: ['ALL=(ALL) NOPASSWD:ALL']
groups: sudo, admin
shell: /bin/bash
power_state:
mode: reboot
message: Restarting after setup
variable "project_name" {
description = "The name of the project"
type = string
}
variable "vm_name" {
description = "The name of the VM"
type = string
}
variable "vm_target_node" {
description = "The name of the Proxmox node to create the VM on"
type = string
}
variable "vm_clone" {
description = "The name of the template to clone"
type = string
}
variable "vm_full_clone" {
description = "Whether to do a full clone or not"
type = bool
default = true
}
variable "vm_hastate" {
description = "The HA state of the VM"
type = string
default = null
}
variable "vm_hagroup" {
description = "The HA group of the VM"
type = string
default = null
}
variable "vm_agent" {
description = "If qemu-guest agent is running on the VM"
type = number
default = 1
}
variable "vm_description" {
description = "The description to set for the VM"
type = string
default = " "
}
variable "vm_qemu_os" {
description = "The OS of the VM"
type = string
default = "l26"
}
variable "vm_memory_minimum" {
description = "The minimum amount of memory to allocate to the VM (in MB). If set to 0 then ballooning is disabled"
type = number
default = 512
}
variable "vm_memory_maximum" {
description = "The maximum amount of memory to allocate to the VM (in MB). If vm_memory_minimum is set to 0 (ballooning disabled) then this is the static amount"
type = number
default = 1024
}
variable "vm_numa" {
description = "Enable NUMA on the VM (if enabled vm_cores should be set to the number of nodes in the NUMA topology)"
type = bool
default = false
}
variable "vm_sockets" {
description = "The number of sockets to allocate to the VM"
type = number
default = 1
}
variable "vm_cores" {
description = "The number of cores to allocate to the VM"
type = number
default = 1
}
variable "vm_cpu" {
description = "The CPU type to allocate to the VM"
type = string
default = "host"
}
variable "vm_hotplug" {
description = "Hotplug features to enable on the VM. Valid values are network,disk,usb,cpu,memory (cpu,memory both require vm_numa to be set to true)"
type = string
default = "network,disk,usb"
}
variable "vm_scsi_controller" {
description = "The SCSI controller model to emulate. Can be lsi, lsi53c810, virtio-scsi-pci, virtio-scsi-single, megasas, or pvscsi."
type = string
default = "lsi"
}
variable "vm_pool" {
description = "The storage pool to create the VM in"
type = string
default = null
}
variable "vm_os_type" {
description = "The OS type of the VM"
type = string
default = "ubuntu"
}
variable "vm_disk_type" {
description = "The disk type of the hdd in the VM. Options: ide, sata, scsi, virtio."
type = string
default = "scsi"
}
variable "vm_disk_storage" {
description = "The storage pool to ciscsireate the VM disk in"
type = string
default = "local"
}
variable "vm_disk_size" {
description = "The size of the VM disk"
type = number
default = "20"
}
variable "vm_disk_format" {
description = "The format of the VM disk"
type = string
default = "raw"
}
variable "vm_disk_ssd" {
description = "Whether the VM disk is an SSD or not"
type = number
default = 0
}
variable "vm_disk_iothread" {
description = "Create one I/O thread per storage controller, rather than a single thread for all I/O. Requires vm_scsi_controller = virtio-scsi-single and a vm_disk_type = scsi or virtio."
type = number
default = 1
}
variable "vm_disk_cache" {
description = "The cache mode of the VM disk. Options: directsync, none, unsafe, writeback, writethrough"
type = string
default = "none"
}
variable "vm_networks" {
description = "The network configuration for the VM"
type = list(object({
bridge = string
firewall = bool
link_down = bool
model = string
tag = number
}))
default = [
{
bridge = "vmbr0"
firewall = false
link_down = false
model = "virtio"
tag = -1
}
]
}
variable "vm_serial_id" {
description = "The ID of the serial device for the VM. Must be unique, and between 0-3 or null to not create a serial device"
type = number
default = null
}
variable "vm_serial_type" {
description = "The type of the serial device for the VM. Can be socket or a dev on the host (e.g. /dev/ttyS0), if you do this you cannot migrate the VM"
type = string
default = null
}
variable "vm_cloudinit_cdrom_storage" {
description = "The storage pool to create the cloud-init cdrom in"
type = string
default = "local"
}
variable "vm_ssh_user" {
description = "The SSH user to use to connect to the VM"
type = string
default = "root"
}
variable "vm_ssh_private_key_path" {
description = "The path the the ssh private key to connect to the VM with"
type = string
default = null
}
variable "vm_ssh_public_key_path" {
description = "The path the the ssh public key to connect to provision with"
type = string
default = null
}
variable "vm_domain_name" {
description = "The domain for the VM"
type = string
default = "localdomain"
}
variable "vm_ipconfig" {
description = "The static IP configuration for the VM, should be 'ip=dhcp' if using DHCP. Format: ip=10.10.120.254/24,gw=10.10.120.1"
type = list(string)
default = ["ip=dhcp"]
}
variable "vm_nameserver" {
description = "The nameserver to use for the VM (only required if not using dhcp)"
type = string
default = null
}
variable "vm_proxmox_ssh_server" {
description = "The IP/Hostname of the server to upload cloud-init files to"
type = string
}
variable "vm_proxmox_ssh_user" {
description = "The SSH user to use to connect to the Proxmox server with. This is used to upload the cloud-init file. This user must have write access to the snippets directory on the datastore used"
type = string
default = "root"
}
variable "vm_proxmox_ssh_private_key_path" {
description = "The path the the ssh private key to connect to the Proxmox server with"
type = string
}
variable "vm_proxmox_snippets_storage_pool" {
description = "The storage pool to create the cloud-init snippets in"
type = string
default = "local"
}
variable "ansible_user" {
description = "The user to use for Ansible"
type = string
default = "ansible"
}
variable "ansible_password" {
description = "The hashed password to use for Ansible"
type = string
default = null
}
variable "ansible_public_key" {
description = "value of the public key to use for Ansible"
type = string
default = null
}
variable "vm_tags" {
description = "The tags to apply to the VM"
type = string
default = null
}
variable "templates_folder" {
description = "The location of the templates folder (default should be fine)"
type = string
default = "./shared/templates"
}
variable "generated_folder" {
description = "The location of the folder that will hold generated files"
type = string
default = "./generated"
}
locals {
template_ci_userdata_filename = "${var.templates_folder}/cloud-init/user-data.tftpl"
serial_added = var.vm_serial_id >= 0 ? true : false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment