Files
infra/tofu/pilot.tf.example
DmitryandClaude Sonnet 5 646f2bbc8f feat(tofu): OpenTofu provisioning scaffold, auth modes and pilot notes
- providers.tf / variables.tf / versions.tf: bpg/proxmox ~> 0.84, endpoint and
  credentials from TF_VAR_* (set by the Makefile tofu-* targets from the
  repo-root .env). Two auth modes: root@pam by password (privileged: features
  beyond nesting, device passthrough, datastore mount points) or the
  ansible@pve token.
- README.md: pilot results on VMID 199 - what the token can and cannot do,
  why a root token still fails the literal `$authuser eq 'root@pam'` check,
  the cmode/console drift finding, and the chosen root@pam-by-password mode.
- pilot.tf.example: reference resource shape (features, device_passthrough,
  mount_point), not loaded (.example).
- .terraform.lock.hcl: pin the provider.

State has no backend yet; tofu/*.tfstate stays local and git-ignored.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uoq5AVK8mkBgg83Mq6o5V
2026-09-03 07:04:23 +03:00

135 lines
5.2 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================================
# ОБРАЗЕЦ, НЕ ЗАГРУЖАЕТСЯ. Расширение .example выбрано намеренно: сам пилот
# (VMID 199) снесён 2026-09-02, и будь этот файл активным, каждый `tofu-plan`
# предлагал бы создать его заново.
#
# Держим как рабочий пример формы ресурса: по нему описываются реальные
# сервисы при переезде. См. docs/ai/migration-tofu.md, шаг 4.2.
# ============================================================================
#
# Пилот: одноразовый LXC, созданный OpenTofu.
# ============================================================================
#
# ЗАЧЕМ
# Проверить на живом кластере ровно те места, из-за которых переезд на Tofu
# выглядел рискованным, не трогая ни один боевой контейнер:
#
# 1. Проброс /dev/fuse. В pve-*.yml он сделан правкой /etc/pve/lxc/<vmid>.conf
# (lxc.cgroup2.devices.allow + lxc.mount.entry), потому что Proxmox API
# сырые lxc.* ключи не принимает. У провайдера для этого есть
# features.fuse — штатный флаг PVE, а не обход.
# 2. Проброс /dev/net/tun — блок device_passthrough (dev0: в PVE 8.2+).
# 3. Mount point на storage вместо bind mount каталога хоста. Именно bind
# mount у gitea (mp0: /opt/data/gitea) требует прав root@pam и не
# создаётся API-токеном; volume на datastore — создаётся.
#
# Контейнер намеренно не входит в inventory и не автозапускается.
# Снести после проверки: make tofu-destroy CONFIRM=1
#
# VMID 199 и 192.168.1.39 выбраны свободными на 2026-09-02 и лежат вне
# диапазона сервисов, но внутри маршрутов ru-vps (192.168.1.5-40).
locals {
# Привилегированный режим = аутентификация root@pam по паролю. Makefile
# выбирает его, когда в корневом .env задан PROXMOX_ROOT_PASSWORD.
privileged = var.pve_password != ""
}
resource "proxmox_virtual_environment_container" "pilot" {
node_name = "cloud-pc"
vm_id = 199
unprivileged = true
start_on_boot = false
started = true
tags = ["tofu", "pilot"]
initialization {
hostname = "tofu-pilot"
ip_config {
ipv4 {
address = "192.168.1.39/24"
gateway = "192.168.1.1"
}
}
dns {
servers = ["1.1.1.1"]
}
user_account {
keys = [trimspace(file(pathexpand("~/.ssh/id_ed25519_homelab.pub")))]
}
}
operating_system {
template_file_id = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst"
type = "debian"
}
cpu {
cores = 1
}
memory {
dedicated = 512
swap = 512
}
disk {
datastore_id = "data"
size = 8
}
# Проверка №1 и №2: то, что в pve-*.yml делается правкой конфига на узле.
# Токену Proxmox разрешает только nesting; keyctl и fuse требуют root@pam.
# null означает «не задавать поле», а не «выключить».
features {
nesting = true
keyctl = local.privileged ? true : null
fuse = local.privileged ? true : null
}
# Проброс устройства Proxmox разрешает только root@pam (403 для токена,
# проверено на пилоте 2026-09-02), поэтому блок появляется лишь в
# привилегированном режиме.
dynamic "device_passthrough" {
for_each = local.privileged ? [1] : []
content {
path = "/dev/net/tun"
}
}
# Проверка №3: volume на datastore, а не bind mount каталога хоста.
mount_point {
volume = "data"
size = "4G"
path = "/opt/pilot-data"
}
network_interface {
name = "eth0"
bridge = "vmbr0"
firewall = true
}
startup {
order = 999
}
# ignore_changes = [features] здесь НЕТ намеренно. Он нужен только в
# гибридной схеме, где features выставляет Ansible через `pct set`: иначе
# Tofu на следующем apply откатывает их и ломает Docker в контейнере
# (проверено на пилоте). В привилегированном режиме features описаны выше
# декларативно, и обход не требуется.
}
output "pilot" {
description = "Что проверять на узле после apply"
value = {
vmid = proxmox_virtual_environment_container.pilot.vm_id
node = proxmox_virtual_environment_container.pilot.node_name
verify = "ssh cloud-pc sudo pct config ${proxmox_virtual_environment_container.pilot.vm_id}"
}
}