- 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
135 lines
5.2 KiB
Plaintext
135 lines
5.2 KiB
Plaintext
# ============================================================================
|
||
# ОБРАЗЕЦ, НЕ ЗАГРУЖАЕТСЯ. Расширение .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}"
|
||
}
|
||
}
|