Restructure: move infra packages to root level
This commit is contained in:
35
terraform-pve/CHECKPOINT.md
Normal file
35
terraform-pve/CHECKPOINT.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Tailscale Subnet Router LXC Deployment — CHECKPOINT
|
||||
|
||||
## Status: 2026-06-11 22:20 UTC
|
||||
|
||||
### Progress
|
||||
- ✅ **3030** (MK33): Online, advertising `192.168.0.0/18`, route approved
|
||||
- ✅ **3031** (MK33): FIXED — tailscaled running, route approved by Bobby in console
|
||||
- ✅ **Skill created:** `tailscale-lxc-subnet-router` — documents 3031 fix + critical route hijacking pitfall
|
||||
- ✅ **Artemis LAN partition FIXED:** `tailscale set --accept-routes=false` restored direct L2 routing
|
||||
- ✅ **Bobby can now SSH directly to Artemis** (was blocked by Tailscale routing table hijacking)
|
||||
- ⏳ **3032/3033** (MK50): Terraform ready — awaiting deploy signal
|
||||
|
||||
### Critical Discovery — Tailscale Route Hijacking
|
||||
**Root cause of Artemis "network partition":** `tailscale set --accept-routes=true` installed kernel routing rules (table 52) that redirected ALL `192.168.0.0/18` traffic through `tailscale0` instead of direct `eno1`.
|
||||
|
||||
| Before Fix | After Fix |
|
||||
|-----------|-----------|
|
||||
| `ip route get 192.168.50.41` → `dev tailscale0` | `ip route get 192.168.50.41` → `dev eno1` ✅ |
|
||||
| Bobby could NOT SSH to Artemis via LAN | Bobby CAN SSH to Artemis via LAN ✅ |
|
||||
| Artemis could NOT reach fleet nodes via LAN | Artemis routing table correct (pings still fail for some nodes — separate issues) |
|
||||
|
||||
**Standing rule:** Artemis must NOT `accept-routes` while advertising `192.168.0.0/18`. Subnet routers (3030/3031) handle tailnet→LAN; Artemis stays direct L2 for LAN peers.
|
||||
|
||||
### 3031 Fix Summary
|
||||
**Root cause:** `/etc/default/tailscaled` missing `PORT` variable → systemd unit `--port=${PORT}` expanded to `--port=` → `INVALIDARGUMENT`
|
||||
**Solution:** `pct exec` from MK33 host, wrote `PORT=41641` + `FLAGS=`, daemon-reload, restart, re-auth with route-capable key
|
||||
|
||||
### Credentials
|
||||
- Latest LXC auth key stored in `fleet.env` as `TAILSCALE_AUTH_KEY_LXC`
|
||||
- MK50 PVE API token exists in `fleet.env`
|
||||
|
||||
### Next Actions
|
||||
1. Deploy 3032/3033 on MK50 via Terraform when Bobby signals
|
||||
2. Verify all 4 LXCs advertise `192.168.0.0/18` and routes approved
|
||||
3. Investigate remaining LAN unreachability for MK50/MK33/Shield (may be their own accept-routes conflicts)
|
||||
6
terraform-pve/Dockerfile
Normal file
6
terraform-pve/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM hashicorp/terraform:latest
|
||||
|
||||
WORKDIR /workspace
|
||||
VOLUME ["/workspace"]
|
||||
|
||||
ENTRYPOINT ["terraform"]
|
||||
55
terraform-pve/PHASE1-TEST-NOTES.md
Normal file
55
terraform-pve/PHASE1-TEST-NOTES.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Phase 1 POC — Test Notes
|
||||
## Date: 2026-06-04
|
||||
## Status: COMPLETE
|
||||
|
||||
## Test Environment
|
||||
- **Node:** MK33 (192.168.7.33)
|
||||
- **PVE Cluster:** pve-swarm (3-node HA, quorate)
|
||||
- **Terraform:** v1.15.5 + bpg/proxmox v0.70.0 (Docker container)
|
||||
- **Auth:** API Token `root@pam!terraform` (privsep=0)
|
||||
- **Template:** `nas-ct-stor:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst`
|
||||
- **Storage:** `local` (dir-based, NOT local-lvm — verified via live API)
|
||||
|
||||
## What Was Tested
|
||||
1. Single LXC creation via Terraform plan → apply
|
||||
2. OS template extraction from NFS-shared storage
|
||||
3. Network: static IPv4 192.168.50.50/18, gateway, DNS
|
||||
4. Console authentication: root password + SSH key injection
|
||||
5. Features: unprivileged=true + nesting=true
|
||||
|
||||
## Results
|
||||
- ✅ LXC-5050 created successfully (4s)
|
||||
- ✅ OS loaded — Debian 12 console accessible
|
||||
- ✅ Root password "ubuntu" confirmed working
|
||||
- ✅ SSH key (artemis_key.pub) provisioned
|
||||
- ✅ No provider warnings or errors
|
||||
|
||||
## Fixes Applied During POC
|
||||
| Issue | Fix |
|
||||
|-------|-----|
|
||||
| `local-lvm` storage didn't exist | Changed to `local` (verified via PVE API) |
|
||||
| Template auto-downloaded to local | Pointed to existing `nas-ct-stor` NFS share |
|
||||
| `.env` + Docker env mapping broken | Replaced with `terraform.auto.tfvars` (native Terraform) |
|
||||
| `run.sh` didn't forward flags | Fixed `${@:2}` handling for `-auto-approve` |
|
||||
| `features { nesting=true }` caused 500 | Combined with `unprivileged=true` — resolved |
|
||||
| No console login credentials | Added `password` to `user_account` block |
|
||||
| Provider schema errors | Verified all attributes live via `terraform providers schema` |
|
||||
|
||||
## Blockers / Tabled
|
||||
- **Pegaprox MK34/MK39 offline:** Tabled for Traefik VNC middleware fix
|
||||
- **Pegaprox console passthrough:** Requires Traefik middleware for SPICE/VNC websocket proxy
|
||||
|
||||
## Files in This Commit
|
||||
- `Dockerfile` — hashicorp/terraform base image
|
||||
- `docker-compose.yml` — volume mounts + working_dir
|
||||
- `run.sh` — wrapper script (executable)
|
||||
- `terraform/providers.tf` — bpg/proxmox provider with API token auth
|
||||
- `terraform/variables.tf` — all configurable parameters
|
||||
- `terraform/main.tf` — single LXC resource
|
||||
- `terraform/terraform.auto.tfvars` — live values (private Gitea)
|
||||
|
||||
## Next Phase
|
||||
Phase 2: Modular LXC deployment
|
||||
- Extract module: `modules/lxc/`
|
||||
- Auto-derive VMID, name, IP from count + vmid_base
|
||||
- Bulk creation: `count=4` → lxc-5050..5053
|
||||
13
terraform-pve/docker-compose.yml
Normal file
13
terraform-pve/docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
terraform:
|
||||
build: .
|
||||
container_name: terraform-pve
|
||||
volumes:
|
||||
- ./terraform:/workspace
|
||||
- ~/.ssh/artemis_key.pub:/workspace/artemis_key.pub:ro
|
||||
- ../ansible-push:/ansible-push
|
||||
working_dir: /workspace
|
||||
network_mode: host
|
||||
stdin_open: true
|
||||
tty: true
|
||||
command: ["version"]
|
||||
24
terraform-pve/run.sh
Executable file
24
terraform-pve/run.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# How to use this file TF_VAR_vmid_base=3550 TF_VAR_lxc_count=4 ./run.sh apply -auto-approve
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Forward all TF_VAR_* environment variables into the container
|
||||
TF_VAR_ARGS=""
|
||||
while IFS='=' read -r name _; do
|
||||
TF_VAR_ARGS="$TF_VAR_ARGS -e $name"
|
||||
done < <(env | grep '^TF_VAR_')
|
||||
|
||||
case "${1:-plan}" in
|
||||
init|validate|plan|apply|destroy)
|
||||
docker compose run --rm $TF_VAR_ARGS terraform "$1" "${@:2}"
|
||||
;;
|
||||
shell)
|
||||
docker compose run --rm $TF_VAR_ARGS terraform sh
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [init|plan|apply|destroy|shell]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
45
terraform-pve/terraform/.terraform.lock.hcl
generated
Normal file
45
terraform-pve/terraform/.terraform.lock.hcl
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/bpg/proxmox" {
|
||||
version = "0.70.0"
|
||||
constraints = "0.70.0"
|
||||
hashes = [
|
||||
"h1:Vq+frhavl4SIBtt7BqGJ4XNjzvWl2lAhA0feK5i4ocg=",
|
||||
"zh:05fe0d04fa07c6f23028e08ebf14ed01f8cb6295c926bdc923b333c1b82263e7",
|
||||
"zh:2507482294e544990946c4ae660843c3c783dca0a104ba41156dadd9f99a6c03",
|
||||
"zh:3b34b8af4890a7c9785335e5367b96a5f2bacd39718ae242e392a2f476cdb47b",
|
||||
"zh:4c81279f32dee51ba760cdee546300c8bf5a00b1be8bafe0fe374e5aeedf38bd",
|
||||
"zh:6e91c968de930e6f1f234019426e5afdfdfbbf40df6cd552708224737ef6fcf4",
|
||||
"zh:8a4fbe6b16c216d3bc54d09eff3fc2812d9ae80fb612361428609fdff4763054",
|
||||
"zh:95c3784147c61ad938781dac3977660882c3018af98371583a55c3dbc5e007ed",
|
||||
"zh:9f781c90ec3e23b3aac9f7a08ba8b44f2909a65e8803ca3a034e8d138b414b4e",
|
||||
"zh:a9e8cbfc490a7ea41e0942498604e5b709ca8967fc38ee934cde23d7aed9762a",
|
||||
"zh:addeab5eb77b10f7d68df07919ca007acbc00ad71f256982d485bdc0a13d0191",
|
||||
"zh:ca111d70f0f365d4b406ff0a0a3477217538a1d1cdd004e8bacfab63af23a83e",
|
||||
"zh:d304a0a7334dce31d66eeaecd67607d2b84b7b37b2615335351268acd6cfd41f",
|
||||
"zh:e3a5e5ec75262320b14988d18f26acefe1e75a6da6a4509cfe5edc707527e465",
|
||||
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
|
||||
"zh:f770d33d287837b6295dc98165e24631f8f683e5d0e5f1a0200f30edc078f516",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/local" {
|
||||
version = "2.9.0"
|
||||
hashes = [
|
||||
"h1:9rBZCMNpxKwMlRbWH2QpwD3kqUCAejdOZQ/aiiDObXQ=",
|
||||
"zh:0baa4566cf77f1ff52f4293d1c8536202dd23edc197c3196413a28343c3ac3a0",
|
||||
"zh:16b5559c3c07088ddad11a9bb9e9c0799999363c2958e9a5be2bcbbf2cd9ca64",
|
||||
"zh:197c79015a10d1cce904a8ea722cbc750c42aeae2da53f44a6a0751d9fd1aa90",
|
||||
"zh:29d0b03e5343a80677ebfeb2e2c31cbe4b1f65e736e53417454a4277fec2544c",
|
||||
"zh:4896bfa6cf1d2fd562b47ef2e87f47862ae92a04f8ad5d764380f0c6653473b8",
|
||||
"zh:531f8529cbca49f681883e57761a05a8398afaef6d1ab0d205d26bf12f4428e8",
|
||||
"zh:6aaf5011d83161c86d2bfb80c0923ec934e578288758da2f37acb7aec129004b",
|
||||
"zh:7430275253d3d3c40aa6179e0ec0d63212874dbbc06c5a51b9d07ec590f9756c",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:be17dc611e95e26cdf6cad79dfccf1064f0e32032a2efeb939a9bbe7fb1cbfe9",
|
||||
"zh:f0e3b0aa644202e1d79d2000dca91f6019425da71e9800fa23f27e51c034f195",
|
||||
"zh:f62bae4519e4ead49182ddc8afe8cf61e2a4c3ba3973b0fbba967736a2696aa3",
|
||||
"zh:fcafa360a5b0b96244f26f4e3a6d642b716a376557142c2442ff2fb12d11da18",
|
||||
]
|
||||
}
|
||||
2
terraform-pve/terraform/artemis_key.pub
Normal file
2
terraform-pve/terraform/artemis_key.pub
Normal file
@@ -0,0 +1,2 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPSBrRCROUHOiZX9IB3teEK89VFfghbdu7OF5NoJ1Y6g Generated By Termius
|
||||
|
||||
13
terraform-pve/terraform/inventory-lxc.tmpl
Normal file
13
terraform-pve/terraform/inventory-lxc.tmpl
Normal file
@@ -0,0 +1,13 @@
|
||||
all:
|
||||
children:
|
||||
lxcs:
|
||||
hosts:
|
||||
%{ for host in hosts ~}
|
||||
${host.hostname}:
|
||||
ansible_host: ${host.ipv4_host}
|
||||
ansible_user: ${host.user}
|
||||
ansible_password: ${host.password}
|
||||
ansible_port: ${host.port}
|
||||
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
|
||||
ansible_python_interpreter: auto_silent
|
||||
%{ endfor ~}
|
||||
41
terraform-pve/terraform/main.tf
Normal file
41
terraform-pve/terraform/main.tf
Normal file
@@ -0,0 +1,41 @@
|
||||
locals {
|
||||
# Generate a list of VMIDs from vmid_base to vmid_base + lxc_count - 1
|
||||
vmids = [for i in range(var.lxc_count) : var.vmid_base + i]
|
||||
|
||||
# Derive IPv4 from each VMID: subnet_prefix + first2digits + last2digits
|
||||
# e.g. vmid 5052 -> 192.168.50.52/18
|
||||
ipv4s = {
|
||||
for vmid in local.vmids :
|
||||
vmid => "${var.subnet_prefix}.${floor(vmid / 100) % 100}.${vmid % 100}/18"
|
||||
}
|
||||
|
||||
# Derive hostnames: name_prefix + vmid
|
||||
hostnames = {
|
||||
for vmid in local.vmids :
|
||||
vmid => "${var.name_prefix}-${vmid}"
|
||||
}
|
||||
}
|
||||
|
||||
module "lxc" {
|
||||
source = "./modules/lxc"
|
||||
|
||||
for_each = toset([for v in local.vmids : tostring(v)])
|
||||
|
||||
vmid = tonumber(each.key)
|
||||
hostname = local.hostnames[tonumber(each.key)]
|
||||
ipv4 = local.ipv4s[tonumber(each.key)]
|
||||
|
||||
node = var.node
|
||||
cores = var.cores
|
||||
memory = var.memory
|
||||
storage = var.storage
|
||||
rootfs_size = var.rootfs_size
|
||||
gateway = var.gateway
|
||||
dns_servers = var.dns_servers
|
||||
ssh_key_path = var.ssh_key_path
|
||||
template_file_id = var.template_file_id
|
||||
password = var.password
|
||||
tags = concat(var.tags, ["vmid-${each.key}"])
|
||||
unprivileged = var.unprivileged
|
||||
devices = var.devices
|
||||
}
|
||||
56
terraform-pve/terraform/main.tf.phase1-backup
Normal file
56
terraform-pve/terraform/main.tf.phase1-backup
Normal file
@@ -0,0 +1,56 @@
|
||||
resource "proxmox_virtual_environment_container" "lxc_test" {
|
||||
node_name = var.node
|
||||
vm_id = var.vmid
|
||||
unprivileged = true
|
||||
|
||||
description = "Terraform test LXC - Phase 1 (${var.hostname})"
|
||||
|
||||
cpu {
|
||||
cores = var.cores
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = var.memory
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = var.storage
|
||||
size = var.rootfs_size
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
}
|
||||
|
||||
features {
|
||||
nesting = true
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = var.hostname
|
||||
|
||||
dns {
|
||||
servers = var.dns_servers
|
||||
}
|
||||
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = var.ipv4
|
||||
gateway = var.gateway
|
||||
}
|
||||
}
|
||||
|
||||
user_account {
|
||||
keys = [file(var.ssh_key_path)]
|
||||
password = var.password
|
||||
}
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = var.template_file_id
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
tags = ["terraform", "phase1", "test"]
|
||||
}
|
||||
79
terraform-pve/terraform/modules/lxc/main.tf
Normal file
79
terraform-pve/terraform/modules/lxc/main.tf
Normal file
@@ -0,0 +1,79 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.70.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_container" "this" {
|
||||
node_name = var.node
|
||||
vm_id = var.vmid
|
||||
unprivileged = var.unprivileged
|
||||
|
||||
description = "Terraform batch LXC — ${var.hostname}"
|
||||
|
||||
cpu {
|
||||
cores = var.cores
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = var.memory
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = var.storage
|
||||
size = var.rootfs_size
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
}
|
||||
|
||||
dynamic "features" {
|
||||
for_each = var.unprivileged ? [1] : []
|
||||
content {
|
||||
nesting = true
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "device_passthrough" {
|
||||
for_each = var.devices
|
||||
content {
|
||||
path = device_passthrough.value.path
|
||||
mode = device_passthrough.value.mode
|
||||
uid = device_passthrough.value.uid
|
||||
gid = device_passthrough.value.gid
|
||||
deny_write = device_passthrough.value.deny_write
|
||||
}
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = var.hostname
|
||||
|
||||
dns {
|
||||
servers = var.dns_servers
|
||||
}
|
||||
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = var.ipv4
|
||||
gateway = var.gateway
|
||||
}
|
||||
}
|
||||
|
||||
user_account {
|
||||
keys = [file(var.ssh_key_path)]
|
||||
password = var.password
|
||||
}
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = var.template_file_id
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
tags = var.tags
|
||||
}
|
||||
19
terraform-pve/terraform/modules/lxc/outputs.tf
Normal file
19
terraform-pve/terraform/modules/lxc/outputs.tf
Normal file
@@ -0,0 +1,19 @@
|
||||
output "vmid" {
|
||||
description = "LXC VMID"
|
||||
value = proxmox_virtual_environment_container.this.vm_id
|
||||
}
|
||||
|
||||
output "hostname" {
|
||||
description = "LXC hostname"
|
||||
value = var.hostname
|
||||
}
|
||||
|
||||
output "ipv4" {
|
||||
description = "LXC static IPv4 with CIDR"
|
||||
value = var.ipv4
|
||||
}
|
||||
|
||||
output "node" {
|
||||
description = "Target PVE node"
|
||||
value = var.node
|
||||
}
|
||||
99
terraform-pve/terraform/modules/lxc/variables.tf
Normal file
99
terraform-pve/terraform/modules/lxc/variables.tf
Normal file
@@ -0,0 +1,99 @@
|
||||
variable "vmid" {
|
||||
description = "LXC VMID"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "hostname" {
|
||||
description = "LXC hostname"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "ipv4" {
|
||||
description = "Static IPv4 with CIDR"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "node" {
|
||||
description = "Target PVE node"
|
||||
type = string
|
||||
default = "mk33"
|
||||
}
|
||||
|
||||
variable "cores" {
|
||||
description = "CPU cores"
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "memory" {
|
||||
description = "RAM in MB"
|
||||
type = number
|
||||
default = 2048
|
||||
}
|
||||
|
||||
variable "storage" {
|
||||
description = "Storage pool"
|
||||
type = string
|
||||
default = "local"
|
||||
}
|
||||
|
||||
variable "rootfs_size" {
|
||||
description = "Root filesystem size in GB"
|
||||
type = number
|
||||
default = 8
|
||||
}
|
||||
|
||||
variable "gateway" {
|
||||
description = "IPv4 gateway"
|
||||
type = string
|
||||
default = "192.168.18.1"
|
||||
}
|
||||
|
||||
variable "dns_servers" {
|
||||
description = "DNS servers"
|
||||
type = list(string)
|
||||
default = ["192.168.7.7", "192.168.18.1", "1.1.1.1"]
|
||||
}
|
||||
|
||||
variable "ssh_key_path" {
|
||||
description = "Path to SSH public key for jarvis user"
|
||||
type = string
|
||||
default = "artemis_key.pub"
|
||||
}
|
||||
|
||||
variable "template_file_id" {
|
||||
description = "LXC OS template file ID (storage:path)"
|
||||
type = string
|
||||
default = "nas-ct-stor:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst"
|
||||
}
|
||||
|
||||
variable "password" {
|
||||
description = "Root password for console login"
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Tags to apply to the LXC"
|
||||
type = list(string)
|
||||
default = ["terraform", "batch"]
|
||||
}
|
||||
|
||||
variable "unprivileged" {
|
||||
description = "Run as unprivileged container"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "devices" {
|
||||
description = "List of device passthrough configs (path, mode, uid, gid, deny_write)"
|
||||
type = list(object({
|
||||
path = string
|
||||
mode = optional(string, "0666")
|
||||
uid = optional(number, 0)
|
||||
gid = optional(number, 0)
|
||||
deny_write = optional(bool, false)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
44
terraform-pve/terraform/outputs.tf
Normal file
44
terraform-pve/terraform/outputs.tf
Normal file
@@ -0,0 +1,44 @@
|
||||
# Timestamp for inventory filename during testing
|
||||
variable "inventory_timestamp" {
|
||||
description = "Timestamp suffix for inventory file (e.g. 2026-06-05-143022). Leave empty for static filename."
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
locals {
|
||||
lxc_hosts = [
|
||||
for vmid in local.vmids : {
|
||||
hostname = module.lxc[tostring(vmid)].hostname
|
||||
ipv4 = module.lxc[tostring(vmid)].ipv4
|
||||
ipv4_host = split("/", module.lxc[tostring(vmid)].ipv4)[0]
|
||||
user = "root"
|
||||
password = var.password
|
||||
port = 22
|
||||
}
|
||||
]
|
||||
|
||||
inventory_filename = var.inventory_timestamp != "" ? "inventory-lxc-${var.inventory_timestamp}.yml" : "inventory-lxc.yml"
|
||||
inventory_content = templatefile("${path.module}/inventory-lxc.tmpl", { hosts = local.lxc_hosts })
|
||||
}
|
||||
|
||||
# Write timestamped inventory file (archive/history)
|
||||
resource "local_file" "inventory_timestamped" {
|
||||
filename = "/ansible-push/terraform-prefill/${local.inventory_filename}"
|
||||
content = local.inventory_content
|
||||
}
|
||||
|
||||
# Write latest inventory file (static name, always overwritten)
|
||||
resource "local_file" "inventory_latest" {
|
||||
filename = "/ansible-push/terraform-prefill/inventory-lxc.yml"
|
||||
content = local.inventory_content
|
||||
}
|
||||
|
||||
output "inventory_path" {
|
||||
description = "Path to generated Ansible inventory file (static latest)"
|
||||
value = local_file.inventory_latest.filename
|
||||
}
|
||||
|
||||
output "inventory_path_archive" {
|
||||
description = "Path to generated Ansible inventory file (timestamped archive)"
|
||||
value = local_file.inventory_timestamped.filename
|
||||
}
|
||||
14
terraform-pve/terraform/providers.tf
Normal file
14
terraform-pve/terraform/providers.tf
Normal file
@@ -0,0 +1,14 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.70.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "proxmox" {
|
||||
endpoint = var.pm_api_url
|
||||
api_token = "${var.pm_api_token_id}=${var.pm_api_token_secret}"
|
||||
insecure = true
|
||||
}
|
||||
11
terraform-pve/terraform/terraform.auto.tfvars
Normal file
11
terraform-pve/terraform/terraform.auto.tfvars
Normal file
@@ -0,0 +1,11 @@
|
||||
pm_api_url = "https://192.168.7.33:8006/api2/json"
|
||||
pm_api_token_id = "root@pam!terraform"
|
||||
pm_api_token_secret = "e0a2de73-261e-41ff-aeea-5e208ed5c2e1"
|
||||
node = "mk33"
|
||||
# vmid_base is passed via TF_VAR_vmid_base or -var at runtime
|
||||
# lxc_count is passed via TF_VAR_lxc_count or -var at runtime
|
||||
gateway = "192.168.18.1"
|
||||
dns_servers = ["192.168.7.7", "192.168.18.1", "1.1.1.1"]
|
||||
ssh_key_path = "artemis_key.pub"
|
||||
template_file_id = "nas-ct-stor:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst"
|
||||
password = "ubuntu"
|
||||
18
terraform-pve/terraform/terraform.tfstate
Normal file
18
terraform-pve/terraform/terraform.tfstate
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 4,
|
||||
"terraform_version": "1.15.5",
|
||||
"serial": 112,
|
||||
"lineage": "3d6e1af6-7224-ba55-3a5b-7381460a1995",
|
||||
"outputs": {
|
||||
"inventory_path": {
|
||||
"value": "/ansible-push/terraform-prefill/inventory-lxc.yml",
|
||||
"type": "string"
|
||||
},
|
||||
"inventory_path_archive": {
|
||||
"value": "/ansible-push/terraform-prefill/inventory-lxc.yml",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [],
|
||||
"check_results": null
|
||||
}
|
||||
18
terraform-pve/terraform/terraform.tfstate.backup
Normal file
18
terraform-pve/terraform/terraform.tfstate.backup
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 4,
|
||||
"terraform_version": "1.15.5",
|
||||
"serial": 111,
|
||||
"lineage": "3d6e1af6-7224-ba55-3a5b-7381460a1995",
|
||||
"outputs": {
|
||||
"inventory_path": {
|
||||
"value": "/ansible-push/terraform-prefill/inventory-lxc.yml",
|
||||
"type": "string"
|
||||
},
|
||||
"inventory_path_archive": {
|
||||
"value": "/ansible-push/terraform-prefill/inventory-lxc.yml",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [],
|
||||
"check_results": null
|
||||
}
|
||||
130
terraform-pve/terraform/variables.tf
Normal file
130
terraform-pve/terraform/variables.tf
Normal file
@@ -0,0 +1,130 @@
|
||||
variable "pm_api_url" {
|
||||
description = "Proxmox API URL"
|
||||
type = string
|
||||
default = "https://192.168.7.33:8006/api2/json"
|
||||
}
|
||||
|
||||
variable "pm_api_token_id" {
|
||||
description = "Proxmox API token ID"
|
||||
type = string
|
||||
default = "root@pam!terraform"
|
||||
}
|
||||
|
||||
variable "pm_api_token_secret" {
|
||||
description = "Proxmox API token secret"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "node" {
|
||||
description = "Target PVE node"
|
||||
type = string
|
||||
default = "mk33"
|
||||
}
|
||||
|
||||
# ── Batch / Dynamic Parameters ───────────────────────────────
|
||||
|
||||
variable "vmid_base" {
|
||||
description = "Starting VMID for the first LXC"
|
||||
type = number
|
||||
default = 5050
|
||||
}
|
||||
|
||||
variable "lxc_count" {
|
||||
description = "Number of LXCs to create"
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "subnet_prefix" {
|
||||
description = "First two octets of IPv4 (e.g. 192.168)"
|
||||
type = string
|
||||
default = "192.168"
|
||||
}
|
||||
|
||||
variable "name_prefix" {
|
||||
description = "Hostname prefix for LXCs"
|
||||
type = string
|
||||
default = "lxc"
|
||||
}
|
||||
|
||||
# ── Static Per-LXC Parameters (fixed for POC) ────────────────
|
||||
|
||||
variable "cores" {
|
||||
description = "CPU cores per LXC"
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "memory" {
|
||||
description = "RAM in MB per LXC"
|
||||
type = number
|
||||
default = 2048
|
||||
}
|
||||
|
||||
variable "storage" {
|
||||
description = "Storage pool"
|
||||
type = string
|
||||
default = "local"
|
||||
}
|
||||
|
||||
variable "rootfs_size" {
|
||||
description = "Root filesystem size in GB"
|
||||
type = number
|
||||
default = 8
|
||||
}
|
||||
|
||||
variable "gateway" {
|
||||
description = "IPv4 gateway"
|
||||
type = string
|
||||
default = "192.168.18.1"
|
||||
}
|
||||
|
||||
variable "dns_servers" {
|
||||
description = "DNS servers"
|
||||
type = list(string)
|
||||
default = ["192.168.7.7", "192.168.18.1", "1.1.1.1"]
|
||||
}
|
||||
|
||||
variable "ssh_key_path" {
|
||||
description = "Path to SSH public key for jarvis user"
|
||||
type = string
|
||||
default = "artemis_key.pub"
|
||||
}
|
||||
|
||||
variable "template_file_id" {
|
||||
description = "LXC OS template file ID (storage:path)"
|
||||
type = string
|
||||
default = "nas-ct-stor:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst"
|
||||
}
|
||||
|
||||
variable "password" {
|
||||
description = "Root password for console login"
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "tags" {
|
||||
description = "Base tags for all LXCs"
|
||||
type = list(string)
|
||||
default = ["terraform", "batch"]
|
||||
}
|
||||
|
||||
variable "unprivileged" {
|
||||
description = "Run as unprivileged container"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "devices" {
|
||||
description = "Device passthrough configs for LXC"
|
||||
type = list(object({
|
||||
path = string
|
||||
mode = optional(string, "0666")
|
||||
uid = optional(number, 0)
|
||||
gid = optional(number, 0)
|
||||
deny_write = optional(bool, false)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
96
terraform-pve/terraform/variables.tf.phase1-backup
Normal file
96
terraform-pve/terraform/variables.tf.phase1-backup
Normal file
@@ -0,0 +1,96 @@
|
||||
variable "pm_api_url" {
|
||||
description = "Proxmox API URL"
|
||||
type = string
|
||||
default = "https://192.168.7.33:8006/api2/json"
|
||||
}
|
||||
|
||||
variable "pm_api_token_id" {
|
||||
description = "Proxmox API token ID"
|
||||
type = string
|
||||
default = "root@pam!terraform"
|
||||
}
|
||||
|
||||
variable "pm_api_token_secret" {
|
||||
description = "Proxmox API token secret"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "node" {
|
||||
description = "Target PVE node"
|
||||
type = string
|
||||
default = "mk33"
|
||||
}
|
||||
|
||||
variable "vmid" {
|
||||
description = "LXC VMID"
|
||||
type = number
|
||||
default = 5050
|
||||
}
|
||||
|
||||
variable "hostname" {
|
||||
description = "LXC hostname"
|
||||
type = string
|
||||
default = "lxc-5050"
|
||||
}
|
||||
|
||||
variable "cores" {
|
||||
description = "CPU cores"
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "memory" {
|
||||
description = "RAM in MB"
|
||||
type = number
|
||||
default = 2048
|
||||
}
|
||||
|
||||
variable "storage" {
|
||||
description = "Storage pool"
|
||||
type = string
|
||||
default = "local"
|
||||
}
|
||||
|
||||
variable "rootfs_size" {
|
||||
description = "Root filesystem size in GB"
|
||||
type = number
|
||||
default = 8
|
||||
}
|
||||
|
||||
variable "ipv4" {
|
||||
description = "Static IPv4 with CIDR"
|
||||
type = string
|
||||
default = "192.168.50.50/18"
|
||||
}
|
||||
|
||||
variable "gateway" {
|
||||
description = "IPv4 gateway"
|
||||
type = string
|
||||
default = "192.168.18.1"
|
||||
}
|
||||
|
||||
variable "dns_servers" {
|
||||
description = "DNS servers"
|
||||
type = list(string)
|
||||
default = ["192.168.7.7", "192.168.18.1", "1.1.1.1"]
|
||||
}
|
||||
|
||||
variable "ssh_key_path" {
|
||||
description = "Path to SSH public key for jarvis user"
|
||||
type = string
|
||||
default = "artemis_key.pub"
|
||||
}
|
||||
|
||||
variable "template_file_id" {
|
||||
description = "LXC OS template file ID (storage:path)"
|
||||
type = string
|
||||
default = "nas-ct-stor:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst"
|
||||
}
|
||||
|
||||
variable "password" {
|
||||
description = "Root password for console login"
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
}
|
||||
Reference in New Issue
Block a user