tf defined vms

This commit is contained in:
counterweight 2025-10-31 08:54:18 +01:00
parent 6f42e43efb
commit 4d8e641466
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
7 changed files with 261 additions and 0 deletions

11
.gitignore vendored
View file

@ -1,3 +1,14 @@
# OpenTofu / Terraform
.terraform/
.tofu/
.terraform.lock.hcl
.tofu.lock.hcl
terraform.tfstate
terraform.tfstate.*
crash.log
*.tfvars
*.tfvars.json
inventory.ini
venv/*
.env

66
tofu/nodito/README.md Normal file
View file

@ -0,0 +1,66 @@
## Nodito VMs with OpenTofu (Proxmox)
This directory lets you declare VMs on the `nodito` Proxmox node and apply with OpenTofu. It clones the Ansible-built template `debian-13-cloud-init` and places disks on the ZFS pool `proxmox-tank-1`.
### Prereqs
- Proxmox API token with VM privileges. Example: user `root@pam`, token name `tofu`.
- OpenTofu installed.
```
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://get.opentofu.org/opentofu.gpg | sudo tee /etc/apt/keyrings/opentofu.gpg >/dev/null
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | sudo gpg --no-tty --batch --dearmor -o /etc/apt/keyrings/opentofu-repo.gpg >/dev/null
sudo chmod a+r /etc/apt/keyrings/opentofu.gpg /etc/apt/keyrings/opentofu-repo.gpg
echo \
"deb [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main
deb-src [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] https://packages.opentofu.org/opentofu/tofu/any/ any main" | \
sudo tee /etc/apt/sources.list.d/opentofu.list > /dev/null
sudo chmod a+r /etc/apt/sources.list.d/opentofu.list
sudo apt-get update
sudo apt-get install -y tofu
tofu version
```
- The Ansible template exists: `debian-13-cloud-init` (VMID 9001 by default).
### Provider Auth
Create a `terraform.tfvars` (copy from `terraform.tfvars.example`) and set:
- `proxmox_api_url` (e.g. `https://nodito:8006/api2/json`)
- `proxmox_api_token_id` (e.g. `root@pam!tofu`)
- `proxmox_api_token_secret`
- `ssh_authorized_keys` (your public key content)
Alternatively, you can export env vars and reference them in a tfvars file.
### Declare VMs
Edit `terraform.tfvars` and fill the `vms` map. Example entry:
```
vms = {
web1 = {
name = "web1"
cores = 2
memory_mb = 2048
disk_size_gb = 20
ipconfig0 = "ip=dhcp" # or "ip=192.168.1.50/24,gw=192.168.1.1"
}
}
```
All VM disks are created on `zfs_storage_name` (defaults to `proxmox-tank-1`). Network attaches to `vmbr0`. VLAN can be set per-VM with `vlan_tag`.
### Usage
```
tofu init
tofu plan -var-file=terraform.tfvars
tofu apply -var-file=terraform.tfvars
```
### Notes
- Clones are full clones by default (`full_clone = true`).
- Cloud-init injects `cloud_init_user` and `ssh_authorized_keys`.
- Disks use `scsi0` on ZFS with `discard` enabled.

67
tofu/nodito/main.tf Normal file
View file

@ -0,0 +1,67 @@
locals {
default_ipconfig0 = "ip=dhcp"
}
resource "proxmox_vm_qemu" "vm" {
for_each = var.vms
name = each.value.name
target_node = var.proxmox_node
vmid = try(each.value.vmid, null)
onboot = true
agent = 1
clone = var.template_name
full_clone = true
vga {
type = "serial0"
}
cpu {
sockets = 1
cores = each.value.cores
type = "host"
}
memory = each.value.memory_mb
scsihw = "virtio-scsi-pci"
boot = "c"
bootdisk = "scsi0"
serial {
id = 0
type = "socket"
}
# Network: bridge vmbr0, optional VLAN tag
network {
id = 0
model = "virtio"
bridge = "vmbr0"
tag = try(each.value.vlan_tag, 0)
}
# Cloud-init: user, ssh keys, IP, and custom snippet for qemu-guest-agent
ciuser = var.cloud_init_user
sshkeys = var.ssh_authorized_keys
ipconfig0 = try(each.value.ipconfig0, local.default_ipconfig0)
cicustom = "user=local:snippets/user-data-qemu-agent.yaml"
# Disk on ZFS storage
disk {
slot = "scsi0"
type = "disk"
storage = var.zfs_storage_name
size = "${each.value.disk_size_gb}G"
# optional flags like iothread/ssd/discard differ by provider versions; keep minimal
}
# Cloud-init CD-ROM so ipconfig0/sshkeys apply
disk {
slot = "ide2"
type = "cloudinit"
storage = var.zfs_storage_name
}
}

8
tofu/nodito/provider.tf Normal file
View file

@ -0,0 +1,8 @@
provider "proxmox" {
pm_api_url = var.proxmox_api_url
pm_api_token_id = var.proxmox_api_token_id
pm_api_token_secret = var.proxmox_api_token_secret
pm_tls_insecure = true
}

View file

@ -0,0 +1,35 @@
proxmox_api_url = "https://nodito:8006/api2/json"
proxmox_api_token_id = "root@pam!tofu"
proxmox_api_token_secret = "REPLACE_ME"
proxmox_node = "nodito"
zfs_storage_name = "proxmox-tank-1"
template_name = "debian-13-cloud-init"
cloud_init_user = "counterweight"
# paste your ~/.ssh/id_ed25519.pub or similar
ssh_authorized_keys = <<EOKEY
ssh-ed25519 AAAA... your-key
EOKEY
vms = {
web1 = {
name = "web1"
vmid = 1101
cores = 2
memory_mb = 2048
disk_size_gb = 20
ipconfig0 = "ip=dhcp"
}
db1 = {
name = "db1"
vmid = 1102
cores = 4
memory_mb = 4096
disk_size_gb = 40
ipconfig0 = "ip=dhcp"
}
}

62
tofu/nodito/variables.tf Normal file
View file

@ -0,0 +1,62 @@
variable "proxmox_api_url" {
description = "Base URL for Proxmox API, e.g. https://nodito:8006/api2/json"
type = string
}
variable "proxmox_api_token_id" {
description = "Proxmox API token ID, e.g. root@pam!tofu"
type = string
sensitive = true
}
variable "proxmox_api_token_secret" {
description = "Proxmox API token secret"
type = string
sensitive = true
}
variable "proxmox_node" {
description = "Target Proxmox node name"
type = string
default = "nodito"
}
variable "zfs_storage_name" {
description = "Proxmox storage name backed by ZFS (from Ansible: zfs_pool_name)"
type = string
default = "proxmox-tank-1"
}
variable "template_name" {
description = "Cloud-init template to clone (created by Ansible)"
type = string
default = "debian-13-cloud-init"
}
variable "cloud_init_user" {
description = "Default cloud-init user"
type = string
default = "counterweight"
}
variable "ssh_authorized_keys" {
description = "SSH public key content to inject via cloud-init"
type = string
sensitive = true
}
variable "vms" {
description = "Map of VMs to create"
type = map(object({
name = string
vmid = optional(number)
cores = number
memory_mb = number
disk_size_gb = number
vlan_tag = optional(number)
ipconfig0 = optional(string) # e.g. "ip=dhcp" or "ip=192.168.1.50/24,gw=192.168.1.1"
}))
default = {}
}

12
tofu/nodito/versions.tf Normal file
View file

@ -0,0 +1,12 @@
terraform {
required_version = ">= 1.6.0"
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "= 3.0.2-rc05"
}
}
}