|
terraform { |
|
required_providers { |
|
proxmox = { |
|
source = "telmate/proxmox" |
|
version = "3.0.2-rc06" |
|
} |
|
} |
|
required_version = ">= 1.0.0" |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Variables |
|
# ------------------------------------------------------------------- |
|
|
|
variable "install_dir" { |
|
description = "Directory where OCP installation files will be created" |
|
type = string |
|
default = "ocp-proxmox" |
|
} |
|
|
|
variable "proxmox_host" { |
|
description = "Proxmox host URL for API calls" |
|
type = string |
|
default = "proxmox.example.com" |
|
} |
|
|
|
variable "proxmox_api_token_id" { |
|
description = "API token ID for ISO upload (format: user@realm!token-name)" |
|
type = string |
|
default = "terraform@pve!terraform-token" |
|
} |
|
|
|
variable "proxmox_api_token_secret" { |
|
description = "API token secret for ISO upload" |
|
type = string |
|
sensitive = true |
|
default = "your-token-secret-here" |
|
} |
|
|
|
variable "iso_storage" { |
|
description = "Proxmox storage for ISO files" |
|
type = string |
|
default = "local" |
|
} |
|
|
|
variable "target_node" { |
|
description = "Proxmox cluster node where VMs will be created" |
|
type = string |
|
default = "proxmox" |
|
} |
|
|
|
variable "masters_cpu" { |
|
description = "CPU allocation for master nodes" |
|
type = number |
|
default = 10 |
|
} |
|
|
|
variable "workers_cpu" { |
|
description = "CPU allocation for worker nodes" |
|
type = number |
|
default = 8 |
|
} |
|
|
|
variable "masters_ram" { |
|
description = "RAM allocation for master nodes (MB)" |
|
type = number |
|
default = 18432 |
|
} |
|
|
|
variable "workers_ram" { |
|
description = "RAM allocation for worker nodes (MB)" |
|
type = number |
|
default = 16384 |
|
} |
|
|
|
variable "num_storages" { |
|
description = "Number of storages to alternate between when creating VMs" |
|
type = number |
|
default = 1 |
|
} |
|
|
|
variable "vm_storage1" { |
|
description = "Primary storage for VM disks" |
|
type = string |
|
default = "local-lvm" |
|
} |
|
|
|
variable "vm_storage2" { |
|
description = "Secondary storage for VM disks (for alternating)" |
|
type = string |
|
default = "local-lvm" |
|
} |
|
|
|
variable "vm_maindisk_size" { |
|
description = "Main disk size for VMs" |
|
type = string |
|
default = "100G" |
|
} |
|
|
|
variable "vm_extradisk_size" { |
|
description = "Extra disk size for worker VMs (LVM storage)" |
|
type = string |
|
default = "50G" |
|
} |
|
|
|
variable "bridge" { |
|
description = "Network bridge for VM interfaces" |
|
type = string |
|
default = "vmbr0" |
|
} |
|
|
|
variable "ssh_pubkey" { |
|
description = "SSH public key to inject" |
|
type = string |
|
} |
|
|
|
# Node definitions |
|
locals { |
|
nodes = [ |
|
{ name = "ocp-master-1", mac = "BC:24:11:44:22:32", extra_disk = false }, |
|
{ name = "ocp-master-2", mac = "BC:24:11:44:22:33", extra_disk = false }, |
|
{ name = "ocp-master-3", mac = "BC:24:11:44:22:34", extra_disk = false }, |
|
{ name = "ocp-worker-1", mac = "BC:24:11:44:22:35", extra_disk = true }, |
|
{ name = "ocp-worker-2", mac = "BC:24:11:44:22:36", extra_disk = true }, |
|
] |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Check required tools are installed |
|
# ------------------------------------------------------------------- |
|
|
|
resource "null_resource" "check_prerequisites" { |
|
provisioner "local-exec" { |
|
command = <<-EOT |
|
set -e |
|
MISSING_TOOLS="" |
|
|
|
if ! command -v ./openshift-install &> /dev/null && ! command -v openshift-install &> /dev/null; then |
|
MISSING_TOOLS="$MISSING_TOOLS openshift-install" |
|
fi |
|
|
|
if ! command -v ./oc &> /dev/null && ! command -v oc &> /dev/null; then |
|
MISSING_TOOLS="$MISSING_TOOLS oc" |
|
fi |
|
|
|
if ! command -v nmstatectl &> /dev/null; then |
|
MISSING_TOOLS="$MISSING_TOOLS nmstatectl" |
|
fi |
|
|
|
if [ -n "$MISSING_TOOLS" ]; then |
|
echo "ERROR: The following required tools are missing:$MISSING_TOOLS" |
|
echo "" |
|
echo "Please install them before running Terraform:" |
|
echo " - openshift-install: Download from https://console.redhat.com/openshift/install" |
|
echo " - oc: Download from https://console.redhat.com/openshift/install" |
|
echo " - nmstatectl: Install via 'dnf install nmstate' or 'apt install nmstate'" |
|
exit 1 |
|
fi |
|
|
|
echo "All required tools are available." |
|
EOT |
|
} |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Generate OCP Agent ISO |
|
# ------------------------------------------------------------------- |
|
|
|
resource "null_resource" "generate_agent_iso" { |
|
depends_on = [null_resource.check_prerequisites] |
|
|
|
triggers = { |
|
install_config_hash = filemd5("${path.module}/install-config.yaml") |
|
agent_config_hash = filemd5("${path.module}/agent-config.yaml") |
|
} |
|
|
|
provisioner "local-exec" { |
|
command = <<-EOT |
|
set -e |
|
mkdir -p ${var.install_dir} |
|
cp install-config.yaml agent-config.yaml ${var.install_dir}/ |
|
./openshift-install agent create image --dir=${var.install_dir} |
|
EOT |
|
} |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Upload ISO to Proxmox |
|
# ------------------------------------------------------------------- |
|
|
|
resource "null_resource" "upload_iso_to_proxmox" { |
|
depends_on = [null_resource.generate_agent_iso] |
|
|
|
triggers = { |
|
iso_generated = null_resource.generate_agent_iso.id |
|
} |
|
|
|
provisioner "local-exec" { |
|
command = <<-EOT |
|
set -e |
|
# Delete existing ISO if present (ignore errors if it doesn't exist) |
|
curl -k -X DELETE \ |
|
"https://${var.proxmox_host}:8006/api2/json/nodes/${var.target_node}/storage/${var.iso_storage}/content/${var.iso_storage}:iso/agent.x86_64.iso" \ |
|
-H "Authorization: PVEAPIToken=${var.proxmox_api_token_id}=${var.proxmox_api_token_secret}" \ |
|
|| true |
|
|
|
# Upload the new ISO |
|
curl -k -X POST \ |
|
"https://${var.proxmox_host}:8006/api2/json/nodes/${var.target_node}/storage/${var.iso_storage}/upload" \ |
|
-H "Authorization: PVEAPIToken=${var.proxmox_api_token_id}=${var.proxmox_api_token_secret}" \ |
|
-F "content=iso" \ |
|
-F "filename=@${var.install_dir}/agent.x86_64.iso" \ |
|
-F "node=${var.target_node}" \ |
|
-F "storage=${var.iso_storage}" |
|
EOT |
|
} |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Proxmox Provider Configuration |
|
# ------------------------------------------------------------------- |
|
|
|
provider "proxmox" { |
|
pm_api_url = "https://${var.proxmox_host}:8006/api2/json" |
|
pm_api_token_id = var.proxmox_api_token_id |
|
pm_api_token_secret = var.proxmox_api_token_secret |
|
pm_tls_insecure = true |
|
pm_parallel = 10 |
|
} |
|
|
|
# ------------------------------------------------------------------- |
|
# Create VMs |
|
# ------------------------------------------------------------------- |
|
|
|
resource "proxmox_vm_qemu" "nodes" { |
|
for_each = { for idx, val in local.nodes : idx => val } |
|
|
|
depends_on = [null_resource.upload_iso_to_proxmox] |
|
|
|
name = each.value.name |
|
target_node = var.target_node |
|
agent = 1 |
|
agent_timeout = 1 |
|
skip_ipv6 = true |
|
|
|
cpu { |
|
cores = can(regex("master", each.value.name)) ? var.masters_cpu : var.workers_cpu |
|
sockets = 1 |
|
type = "host" |
|
} |
|
|
|
memory = can(regex("master", each.value.name)) ? var.masters_ram : var.workers_ram |
|
balloon = 1 |
|
scsihw = "virtio-scsi-single" |
|
tags = "ocp" |
|
|
|
# Primary disk |
|
disk { |
|
slot = "scsi0" |
|
size = var.vm_maindisk_size |
|
type = "disk" |
|
storage = var.num_storages > 1 ? (tonumber(each.key) % 2 == 1 ? var.vm_storage1 : var.vm_storage2) : var.vm_storage1 |
|
emulatessd = true |
|
discard = true |
|
iothread = true |
|
} |
|
|
|
# Boot ISO |
|
disk { |
|
slot = "ide2" |
|
type = "cdrom" |
|
iso = "local:iso/agent.x86_64.iso" |
|
} |
|
|
|
# Extra disk for workers (LVM storage) |
|
dynamic "disk" { |
|
for_each = each.value.extra_disk ? [1] : [] |
|
content { |
|
slot = "scsi1" |
|
size = var.vm_extradisk_size |
|
type = "disk" |
|
storage = var.num_storages > 1 ? (tonumber(each.key) % 2 == 1 ? var.vm_storage1 : var.vm_storage2) : var.vm_storage1 |
|
emulatessd = true |
|
discard = true |
|
iothread = true |
|
} |
|
} |
|
|
|
network { |
|
id = 0 |
|
model = "virtio" |
|
bridge = var.bridge |
|
macaddr = each.value.mac |
|
} |
|
|
|
sshkeys = var.ssh_pubkey |
|
|
|
lifecycle { |
|
create_before_destroy = true |
|
} |
|
} |