From 88242af90004d5a0ef286357e055c950ea387648 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Sat, 17 Oct 2026 21:04:00 +0300 Subject: [PATCH] feat: add minimal PROD VM example Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- AGENTS.md | 24 ++- vm_v3_minimal/README.md | 127 ++++++++++++++ vm_v3_minimal/edge.tf | 35 ++++ vm_v3_minimal/network.tf | 35 ++++ vm_v3_minimal/outputs.tf | 38 ++++ vm_v3_minimal/provider.tf | 6 + vm_v3_minimal/secrets.auto.tfvars.example | 3 + vm_v3_minimal/terraform.tfvars.example | 74 ++++++++ vm_v3_minimal/variables.tf | 203 ++++++++++++++++++++++ vm_v3_minimal/vdc.tf | 32 ++++ vm_v3_minimal/versions.tf | 11 ++ vm_v3_minimal/vm.tf | 77 ++++++++ 12 files changed, 660 insertions(+), 5 deletions(-) create mode 100644 vm_v3_minimal/README.md create mode 100644 vm_v3_minimal/edge.tf create mode 100644 vm_v3_minimal/network.tf create mode 100644 vm_v3_minimal/outputs.tf create mode 100644 vm_v3_minimal/provider.tf create mode 100644 vm_v3_minimal/secrets.auto.tfvars.example create mode 100644 vm_v3_minimal/terraform.tfvars.example create mode 100644 vm_v3_minimal/variables.tf create mode 100644 vm_v3_minimal/vdc.tf create mode 100644 vm_v3_minimal/versions.tf create mode 100644 vm_v3_minimal/vm.tf diff --git a/AGENTS.md b/AGENTS.md index 685ae2f..e4db51d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -74,14 +74,15 @@ Terraform. Репозиторий — **эталонные примеры**, н | Папка | Что это | Состояние | Документация | |---|---|---|---| -| **`fullpipe_chain/`** | vDC → Edge → внешние IP → SNAT → vApp → ВМ → Штурвал (полная цепочка) | **рекомендовано использовать** — повторяет рабочую конфигурацию стенда | `/nubes-dev/curated/pipeline/vdc_edge_ip_snat/` | +| **`vm_v3_minimal/`** | ручная организация → vDC → Edge → 3 IP → SNAT → vApp → одна ВМ, без Штурвала | отдельный VM-сценарий, проверенный на PROD 2026-10-17 | — | +| **`fullpipe_chain/`** | vDC → Edge → внешние IP → SNAT → vApp → ВМ → Штурвал (полная цепочка) | расширенный сценарий с Штурвалом; VM/vApp в прежнем опыте пользователя не удалось завершить из-за проблемы с vApp | `/nubes-dev/curated/pipeline/vdc_edge_ip_snat/` | | **`Maria_CRUD/`** | MariaDB + три приложения (Lucee/Flask/Node.js) + HTTP-проверка | проверен на TEST-стенде | `/nubes-test/curated/mariadb/three_apps/` | | `CRUD/` | PostgreSQL + три приложения (Lucee/Flask/Node.js) | черновик (устаревшая схема, старый пин провайдера) — **с оговорками** | `/nubes-test/curated/crud/three_apps/` | | `modify_resources/` | внешние IP на организации + SNAT на шлюзе (для уже существующих услуг) | черновик | — | -**Что рекомендовать пользователю:** `fullpipe_chain` (полный цикл) или `Maria_CRUD` -(проверенный CRUD-пример). Остальные папки — черновики от прошлых работ: могут содержать -неактуальные версии провайдера и работать некорректно. Не выдавай черновик за рабочий образец. +**Что рекомендовать пользователю:** для отдельной ВМ — `vm_v3_minimal`; для сценария +с Штурвалом — `fullpipe_chain`; для CRUD — `Maria_CRUD`. Не используй `fullpipe_chain` +как доказательство успешного самостоятельного развёртывания VM/vApp. --- @@ -235,6 +236,20 @@ provider "nubes" { `terraform.tfvars`: `api_token`, `organization`, `nsxt_uid` (UUID шлюза Edge из карточки услуги), `ip_space_name`, `ip_count`. +### 6.5. `vm_v3_minimal` — одна ВМ без дополнительных рабочих нагрузок + +Создаёт только цепочку **vDC → Edge → выделение IP → SNAT → vApp → ВМ** внутри +организации, которую пользователь предварительно создал вручную в ЛК. Штурвал, +базы данных и приложения в пример не входят. + +**Минимум IP для проверенного PROD-сценария — 3.** При `org_vip_count = 2` API +сообщил, что свободных IP нет и для создания ВМ требуется ещё один; с `3` развёртывание +ВМ запустилось. Если другие услуги используют тот же ipSpace, квоту нужно увеличить. +Не делай вывод о занятых адресах только по статусам услуг в ЛК. + +Пример основан на отдельном сценарии `PROD_STAND/VM_TF_Docs`; он не зависит от +`fullpipe_chain` и не включает его дополнительные ресурсы. + --- ## 7. Секреты — жёсткое правило @@ -352,4 +367,3 @@ provider "nubes" { | **HCL** | язык конфигурации Terraform (файлы `.tf`) | | `terraform.tfvars` | файл значений переменных; в этом репозитории — в `.gitignore` | | `terraform.tfstate` | файл состояния Terraform; хранит соответствие «код ↔ облако» | - diff --git a/vm_v3_minimal/README.md b/vm_v3_minimal/README.md new file mode 100644 index 0000000..135daa6 --- /dev/null +++ b/vm_v3_minimal/README.md @@ -0,0 +1,127 @@ +# Минимальная цепочка для одной ВМ (PROD) + +Пример создаёт одну ВМ и только необходимые для неё услуги: + +```text +организация (создана вручную в ЛК) + -> vDC + -> Edge с routed-сетью + -> выделение IP организации (минимум 3) + -> SNAT + -> vApp + -> одна ВМ +``` + +Штурвал, базы данных и приложения в примере отсутствуют. Он основан на успешно +запущенной в PROD конфигурации `VM_TF_Docs`, а не на `fullpipe_chain`. +Провайдер зафиксирован на PROD-версии `1.5.0`. + +## Важное условие: организация создаётся вручную + +До запуска создайте организацию **«Организация в Cloud Director»** через ЛК. Terraform +не создаёт и не удаляет организацию: `nubes_vc_vdc` получает её имя или UUID через +`organization`. + +В ЛК проверьте, что организации доступны выбранные resource pool, Provider VDC, +storage policy и IP space. Значения из примера (`msk1`, `Intel Cascade Lake 3.1`, +`SSD SDS`) подтверждены для использованного PROD-пула; для другого пула их нужно +заменить на значения из ЛК. + +## Почему выделяется 3 IP + +Для проверенной цепочки с одной ВМ минимальное значение `org_vip_count` — **3**. +При значении 2 API сообщил, что свободных IP — 0, а для операции требуется ещё 1; +при значении 3 развёртывание ВМ запустилось. Поэтому в этом примере не уменьшайте +квоту до 2, даже если из дополнительных потребителей IP оставлена только одна ВМ. + +`org_vip_count` задаёт количество IP в выбранном `ip_space_name` на организации — +это не количество адресов, которое сама ВМ получит. Точное внутреннее распределение +резервов платформой эта конфигурация не показывает. Если другие услуги используют +адреса из того же IP space или там уже есть занятые адреса, квоту нужно увеличить. +Список услуг со статусами `running`/`suspended` сам по себе не показывает, какие IP +заняты. + +В конфигурации VM установлен `same_snat = true`: согласно PROD-схеме при этом для ВМ +создаётся собственный внешний IP. SNAT на Edge также задаётся отдельным ресурсом, +как в проверенной цепочке. + +## Подготовка параметров + +1. Скопируйте шаблоны: + + ```bash + cp terraform.tfvars.example terraform.tfvars + cp secrets.auto.tfvars.example secrets.auto.tfvars + ``` + +2. В `secrets.auto.tfvars` замените заглушку на PROD API token из ЛК → Профиль → + Токены → «Технический». Не присылайте и не коммитьте этот файл. +3. В `terraform.tfvars` замените: + - `organization` на имя или UUID вручную созданной организации; + - `ip_space_name` на точное имя IP space из ЛК; + - `vm_user_public_key` на содержимое вашего `~/.ssh/id_ed25519.pub`; + - `vm_access_ip_list` на доверенный публичный IP/CIDR для входящего доступа. +4. Убедитесь, что имена vDC, Edge, vApp и ВМ уникальны в организации. Не оставляйте + значения-заглушки `REPLACE_WITH_...`. +5. Если выбранный resource pool отличается от проверенного PROD-пула, замените + `vdc_network_provider`, `vdc_provider_vdc`, `vdc_storage_config`, DNS и routed subnet + на значения, допустимые в ЛК. Routed subnet `/24` не должен пересекаться с другой сетью. + +Все переменные и значения по умолчанию прокомментированы в `variables.tf` и +`terraform.tfvars.example`. Параметры ресурсов сверены с PROD YAML-схемами. + +## Запуск + +Команды выполняет владелец инфраструктуры; `apply` в этом примере не запускался: + +```bash +terraform init +terraform validate +terraform plan +``` + +Проверьте план: ожидаются шесть услуг — vDC, Edge, выделение IP на организации, +SNAT, vApp и ВМ. Убедитесь, что в плане нет неожиданных изменений уже существующих +услуг. Только после проверки владелец запускает: + +```bash +terraform apply +``` + +После завершения: + +```bash +terraform output vm_state_flat +``` + +`externalConnect` — внешний адрес ВМ, `internalConnect` — адрес в routed-сети, +`fqdn` — DNS-имя, если платформа его вернула. + +## Параметры ВМ и операции + +- Образ `Ubuntu_22-20G` включает базовый диск 20 GB; `vm_disk = 128` задаёт + **дополнительный** диск. +- `vm_access_port_list` разрешает только заданные порты. `vm_access_ip_list` ограничивает + адреса-источники; не оставляйте доступ SSH открытым для `0.0.0.0/0`, если это не требуется. +- `git_revision` оставлен `null` при создании. Новое значение этого маркера запускает + redeploy при последующем Update. +- `reconcile_trigger` также оставлен `null` при создании. Новое значение запускает + reconcile при Update; при Create reconcile не выполняется. +- В проверке PROD от 17.10.2026 файл-маркер в `/home/ubuntu` отсутствовал после redeploy. + Считайте локальные данные ВМ потенциально теряемыми при redeploy и храните важные данные + вне системного диска. + +## Состав файлов + +| Файл | Назначение | +|---|---| +| `versions.tf` | Версия Terraform и PROD-провайдера | +| `provider.tf` | Подключение к PROD API | +| `variables.tf` | Типы, значения по умолчанию и пояснения к входным переменным | +| `vdc.tf` | Виртуальный датацентр | +| `edge.tf` | Edge и routed-сеть | +| `network.tf` | Квота IP организации и SNAT | +| `vm.tf` | vApp и одна ВМ | +| `outputs.tf` | Идентификаторы услуг и состояние ВМ | +| `terraform.tfvars.example` | Несекретные значения и параметры примера | +| `secrets.auto.tfvars.example` | Шаблон локального файла для API token | diff --git a/vm_v3_minimal/edge.tf b/vm_v3_minimal/edge.tf new file mode 100644 index 0000000..c459f56 --- /dev/null +++ b/vm_v3_minimal/edge.tf @@ -0,0 +1,35 @@ +# Create the perimeter gateway and its routed network inside the VDC. +resource "nubes_vc_nsxt" "edge" { + # Name shown for this Edge service in the personal account. + resource_name = var.nsxt_resource_name + + # Attach the gateway directly to a VDC, not to a VDC group. + vdc_type = "vdc" + + # UUID of the VDC created above; this reference also orders creation. + vdc_uid = nubes_vc_vdc.vdc.id + + # AVI/ALB is not needed for this standalone VM example. + need_enable_avi = false + + # Only required when AVI/ALB is enabled; keep it null when ALB is disabled. + virtual_services_count = null + + # Routed subnet and DNS servers assigned to VMs behind this Edge. + routed_net_configuration = { + # Non-overlapping /24 range for the routed network. + ip_addr_pool = var.nsxt_ip_addr_pool + + # Primary DNS server configured in VMs. + main_dns = var.nsxt_main_dns + + # Secondary DNS server configured in VMs. + second_dns = var.nsxt_second_dns + } + + # Allow provider destroy handling to delete the Edge when dependencies permit. + keep_on_destroy = false + + # Reuse an existing same-name Edge rather than failing during Create. + adopt_existing_on_create = true +} diff --git a/vm_v3_minimal/network.tf b/vm_v3_minimal/network.tf new file mode 100644 index 0000000..9d0c628 --- /dev/null +++ b/vm_v3_minimal/network.tf @@ -0,0 +1,35 @@ +# Allocate organization-level public IP capacity after the VDC and Edge exist. +resource "nubes_vc_org_ip_allocation" "org_ip" { + # Existing organization used by the VDC. + organization = var.organization + + # Configure the selected IP space with the tested minimum count of 3. + # The API expects count as a string inside the vIPConfigure JSON array. + vip_configure = jsonencode([ + { + name = var.ip_space_name + count = tostring(var.org_vip_count) + } + ]) + + # Keep the organization allocation when this Terraform resource is destroyed. + keep_on_destroy = true + + # PROD exposes the organization's usable IP spaces after the VDC and Edge exist. + depends_on = [nubes_vc_nsxt.edge] +} + +# Enable the tested SNAT configuration on the Edge using the same IP space. +resource "nubes_vc_nsxt_snat" "snat" { + # UUID of the Edge created above. + nsxt_uid = nubes_vc_nsxt.edge.id + + # IP space allocated to the organization in the resource above. + ip_space_name = var.ip_space_name + + # Leave SNAT enabled when this Terraform resource is destroyed. + keep_on_destroy = true + + # The IP space must be allocated before SNAT is configured. + depends_on = [nubes_vc_org_ip_allocation.org_ip] +} diff --git a/vm_v3_minimal/outputs.tf b/vm_v3_minimal/outputs.tf new file mode 100644 index 0000000..2ca2b5a --- /dev/null +++ b/vm_v3_minimal/outputs.tf @@ -0,0 +1,38 @@ +# UUID of the created VDC. +output "vdc_id" { + description = "UUID of the VDC." + value = nubes_vc_vdc.vdc.id +} + +# UUID of the created Edge. +output "edge_id" { + description = "UUID of the Edge gateway." + value = nubes_vc_nsxt.edge.id +} + +# UUID of the created vApp. +output "vapp_id" { + description = "UUID of the vApp." + value = nubes_vapp.vapp.id +} + +# UUID of the created VM. +output "vm_id" { + description = "UUID of the VM." + value = nubes_vc_vm_v3.vm.id +} + +# VM IP addresses and connection data returned by the API. +output "vm_state_flat" { + description = "Flat VM state; inspect externalConnect, internalConnect, and fqdn." + value = nubes_vc_vm_v3.vm.state_out_flat +} + +# The configured organization allocation count, not the count of addresses in use. +output "org_ip_allocation" { + description = "Configured IP-space name and organization allocation count." + value = { + ip_space_name = var.ip_space_name + count = var.org_vip_count + } +} diff --git a/vm_v3_minimal/provider.tf b/vm_v3_minimal/provider.tf new file mode 100644 index 0000000..086a568 --- /dev/null +++ b/vm_v3_minimal/provider.tf @@ -0,0 +1,6 @@ +# Connect to the Nubes PROD API. The token is stored separately in +# secrets.auto.tfvars and must never be committed. +provider "nubes" { + api_token = var.api_token + api_endpoint = var.api_endpoint +} diff --git a/vm_v3_minimal/secrets.auto.tfvars.example b/vm_v3_minimal/secrets.auto.tfvars.example new file mode 100644 index 0000000..515fc45 --- /dev/null +++ b/vm_v3_minimal/secrets.auto.tfvars.example @@ -0,0 +1,3 @@ +# Copy to secrets.auto.tfvars and insert a Nubes PROD API token. +# secrets.auto.tfvars is ignored by git; never commit the real token. +api_token = "REPLACE_WITH_NUBES_PROD_API_TOKEN" diff --git a/vm_v3_minimal/terraform.tfvars.example b/vm_v3_minimal/terraform.tfvars.example new file mode 100644 index 0000000..f364b4f --- /dev/null +++ b/vm_v3_minimal/terraform.tfvars.example @@ -0,0 +1,74 @@ +# Copy this file to terraform.tfvars and replace organization-specific values. +# Put the API token only in secrets.auto.tfvars, never in this file. + +# Existing organization created manually in the Nubes personal account. +organization = "REPLACE_WITH_ORGANIZATION_NAME_OR_UUID" + +# Exact IP space visible to this organization in the personal account. +ip_space_name = "internet-no-antiddos-v1" + +# Tested minimum for this VM-only PROD chain. Two IPs left no free address +# when the VM requested its external IP; three allowed the deployment to start. +org_vip_count = 3 + +# API endpoint for the PROD stand. +api_endpoint = "https://lk-api-gateway.ngcloud.ru/api/v1/svc" + +# Unique VDC service name. +vdc_resource_name = "vm-minimal-vdc" + +# Values from the tested PROD resource pool. Replace with values available +# to the manually created organization if its resource pool differs. +vdc_network_provider = "msk1" +vdc_provider_vdc = "Intel Cascade Lake 3.1" + +# VDC capacity: vCPU, guaranteed share (0/50/80), and RAM in GB. +vdc_cpu_allocated = 8 +vdc_cpu_guaranteed = 0 +vdc_mem_allocated = 200 + +# JSON array of storage policies available to the selected Provider VDC. +# Confirm the policy name and size in the personal account before applying. +vdc_storage_config = "[{\"name\":\"SSD SDS\",\"size\":\"2000\"}]" + +# Unique Edge service name. +nsxt_resource_name = "vm-minimal-edge" + +# Non-overlapping /24 routed subnet plus primary and secondary VM DNS servers. +nsxt_ip_addr_pool = "10.10.102.0/24" +nsxt_main_dns = "81.22.46.22" +nsxt_second_dns = "185.247.187.77" + +# Unique vApp service name and vApp name. +vapp_resource_name = "vm-minimal-vapp" +vapp_name = "vm-minimal-vapp" + +# Unique VM service name and hostname/IP-set name. +vm_resource_name = "vm-minimal" +vm_name = "vm-minimal" + +# Tested VM sizing: Ubuntu base image (20 GB) plus 128 GB additional disk. +vm_image = "Ubuntu_22-20G" +vm_cpu = 2 +vm_ram = 4 +vm_disk = 128 + +# Linux account name and your OpenSSH PUBLIC key. +vm_user_login = "ubuntu" +vm_user_public_key = "ssh-ed25519 REPLACE_WITH_YOUR_PUBLIC_KEY" + +# Inbound ports. Narrow the source CIDR below to trusted addresses. +vm_access_port_list = [ + { port = "22", type = "tcp" }, + { port = "80", type = "tcp" } +] +vm_access_ip_list = ["REPLACE_WITH_YOUR_PUBLIC_IP/32"] + +# The tested VM gets its own external IP; do not change without checking +# the consequences for inbound access. +vm_same_snat = true + +# Keep both triggers null for initial creation. To request an operation later, +# set its marker to a new, unique value. +git_revision = null +reconcile_trigger = null diff --git a/vm_v3_minimal/variables.tf b/vm_v3_minimal/variables.tf new file mode 100644 index 0000000..c525dfb --- /dev/null +++ b/vm_v3_minimal/variables.tf @@ -0,0 +1,203 @@ +# ============================================================================= +# Inputs for the standalone PROD VM example. +# Values that depend on the organization or resource pool are in +# terraform.tfvars.example; the API token is in secrets.auto.tfvars.example. +# ============================================================================= + +variable "api_token" { + type = string + sensitive = true + description = "Nubes PROD API token from the Technical token section in the personal account." +} + +variable "api_endpoint" { + type = string + default = "https://lk-api-gateway.ngcloud.ru/api/v1/svc" + description = "Nubes PROD API endpoint. Change only when targeting another stand." +} + +variable "organization" { + type = string + description = "Name or UUID of the Cloud Director organization created manually in the personal account." +} + +variable "ip_space_name" { + type = string + description = "Exact IP space name available to this organization; used for the allocation, Edge SNAT, and VM." +} + +variable "org_vip_count" { + type = number + default = 3 + description = "Organization IP allocation count. Three is the tested minimum for this VM-only deployment; increase if other services need IPs from this space." + + validation { + condition = var.org_vip_count >= 3 && floor(var.org_vip_count) == var.org_vip_count + error_message = "This tested VM-only example requires at least 3 IPs; use a whole number and increase it for additional consumers." + } +} + +variable "vdc_resource_name" { + type = string + default = "vm-minimal-vdc" + description = "Unique service name for the virtual data center." +} + +variable "vdc_network_provider" { + type = string + default = "msk1" + description = "Network provider selected for this organization in the VDC creation form." +} + +variable "vdc_provider_vdc" { + type = string + default = "Intel Cascade Lake 3.1" + description = "Provider VDC selected in the personal account; it must be compatible with the network provider." +} + +variable "vdc_cpu_allocated" { + type = number + default = 8 + description = "Number of vCPUs allocated to the VDC." +} + +variable "vdc_cpu_guaranteed" { + type = number + default = 0 + description = "Guaranteed vCPU percentage. PROD schema allows 0, 50, or 80; this value is fixed at VDC creation." + + validation { + condition = contains([0, 50, 80], var.vdc_cpu_guaranteed) + error_message = "vdc_cpu_guaranteed must be 0, 50, or 80." + } +} + +variable "vdc_mem_allocated" { + type = number + default = 200 + description = "Memory allocated to the VDC, in GB." +} + +variable "vdc_storage_config" { + type = string + default = "[{\"name\":\"SSD SDS\",\"size\":\"2000\"}]" + description = "JSON array of storage policies available to the selected Provider VDC; size is in GB." +} + +variable "nsxt_resource_name" { + type = string + default = "vm-minimal-edge" + description = "Unique service name for the perimeter Edge gateway." +} + +variable "nsxt_ip_addr_pool" { + type = string + default = "10.10.102.0/24" + description = "Unused /24 routed-network range for this Edge. Verify that it does not overlap another network." +} + +variable "nsxt_main_dns" { + type = string + default = "81.22.46.22" + description = "Primary DNS server assigned to VMs on the routed network." +} + +variable "nsxt_second_dns" { + type = string + default = "185.247.187.77" + description = "Secondary DNS server assigned to VMs on the routed network." +} + +variable "vapp_resource_name" { + type = string + default = "vm-minimal-vapp" + description = "Unique service name for the vApp in the personal account." +} + +variable "vapp_name" { + type = string + default = "vm-minimal-vapp" + description = "Unique vApp name matching the platform pattern; it is used when forming the VM DNS name." +} + +variable "vm_resource_name" { + type = string + default = "vm-minimal" + description = "Unique service name for the virtual machine in the personal account." +} + +variable "vm_name" { + type = string + default = "vm-minimal" + description = "VM name matching the platform pattern; it also identifies the VM IP set." +} + +variable "vm_image" { + type = string + default = "Ubuntu_22-20G" + description = "Available PROD VM image. The base disk size is part of the image and cannot be changed here." +} + +variable "vm_cpu" { + type = number + default = 2 + description = "Number of VM vCPUs (PROD schema range: 1-64)." +} + +variable "vm_ram" { + type = number + default = 4 + description = "VM memory in GB (PROD schema range: 1-256)." +} + +variable "vm_disk" { + type = number + default = 128 + description = "Additional VM disk size in GB. The image supplies the separate base disk." +} + +variable "vm_user_login" { + type = string + default = "ubuntu" + description = "Linux account created for SSH access; it is set during VM creation." +} + +variable "vm_user_public_key" { + type = string + description = "Your OpenSSH public key, such as the contents of ~/.ssh/id_ed25519.pub. Never put a private key here." +} + +variable "vm_access_port_list" { + type = list(object({ + port = string + type = string + })) + default = [ + { port = "22", type = "tcp" }, + { port = "80", type = "tcp" } + ] + description = "Inbound VM ports and protocols. Restrict this list to the services the VM actually needs." +} + +variable "vm_access_ip_list" { + type = list(string) + description = "Source IP addresses or CIDRs allowed to reach the VM. Set this to trusted addresses; avoid 0.0.0.0/0 where possible." +} + +variable "vm_same_snat" { + type = bool + default = true + description = "When true, the VM is published through its own external IP created during deployment." +} + +variable "git_revision" { + type = string + default = null + description = "Optional redeploy trigger. Set a new non-empty marker to request redeploy on Update; leave null for normal VM creation." +} + +variable "reconcile_trigger" { + type = string + default = null + description = "Optional reconcile trigger. Change the marker to request reconcile on Update; reconcile does not run on Create." +} diff --git a/vm_v3_minimal/vdc.tf b/vm_v3_minimal/vdc.tf new file mode 100644 index 0000000..1368b9f --- /dev/null +++ b/vm_v3_minimal/vdc.tf @@ -0,0 +1,32 @@ +# Create a VDC inside the organization that already exists in the personal account. +resource "nubes_vc_vdc" "vdc" { + # Name shown for this VDC service in the personal account. + resource_name = var.vdc_resource_name + + # Existing organization name or UUID; this example does not create the organization. + organization_uid = var.organization + + # Resource-platform network provider chosen for this organization. + network_provider = var.vdc_network_provider + + # Provider VDC compatible with the selected network provider. + provider_vdc = var.vdc_provider_vdc + + # vCPU capacity allocated to the VDC. + cpu_allocated = var.vdc_cpu_allocated + + # Guaranteed share of allocated vCPU; PROD accepts 0, 50, or 80. + cpu_guaranteed = var.vdc_cpu_guaranteed + + # Memory capacity allocated to the VDC, in GB. + mem_allocated = var.vdc_mem_allocated + + # JSON storage-policy array; each policy name must exist in the selected Provider VDC. + storage_config = var.vdc_storage_config + + # Suspend the VDC rather than fully deleting it on terraform destroy. + suspend_on_destroy = true + + # Adopt an existing same-name VDC instead of failing during Create. + adopt_existing_on_create = true +} diff --git a/vm_v3_minimal/versions.tf b/vm_v3_minimal/versions.tf new file mode 100644 index 0000000..26c5a43 --- /dev/null +++ b/vm_v3_minimal/versions.tf @@ -0,0 +1,11 @@ +# This standalone example targets the tested Nubes PROD provider. +terraform { + required_version = ">= 1.5.0" + + required_providers { + nubes = { + source = "tf-registry.containerk8s.services.ngcloud.ru/nubes/nubes" + version = "1.5.0" + } + } +} diff --git a/vm_v3_minimal/vm.tf b/vm_v3_minimal/vm.tf new file mode 100644 index 0000000..3e176e9 --- /dev/null +++ b/vm_v3_minimal/vm.tf @@ -0,0 +1,77 @@ +# Create the vApp after the VDC, Edge, organization IP allocation, and SNAT are ready. +resource "nubes_vapp" "vapp" { + # Name shown for this vApp service in the personal account. + resource_name = var.vapp_resource_name + + # vApp name; must be unique in the organization and match the platform naming pattern. + vapp_name = var.vapp_name + + # UUID of the VDC where the vApp will reside. + vdc_uid = nubes_vc_vdc.vdc.id + + # UUID of the Edge whose routed network will be used by the vApp. + nsxt_uid = nubes_vc_nsxt.edge.id + + # Suspend the vApp rather than fully deleting it on terraform destroy. + suspend_on_destroy = true + + # Adopt an existing same-name vApp rather than failing during Create. + adopt_existing_on_create = true + + # The tested PROD vApp deployment requires the IP/SNAT configuration to be ready. + depends_on = [nubes_vc_nsxt_snat.snat] +} + +# Create one VM inside the vApp. +resource "nubes_vc_vm_v3" "vm" { + # Name shown for this VM service in the personal account. + resource_name = var.vm_resource_name + + # VM hostname/IP-set name; it must match the platform naming pattern. + vm_name = var.vm_name + + # UUID of the vApp created above. + vapp_uid = nubes_vapp.vapp.id + + # Operating-system image; its base disk is separate from vm_disk. + image_vm = var.vm_image + + # Number of vCPUs allocated to the VM. + vm_cpu = var.vm_cpu + + # VM memory in GB. + vm_ram = var.vm_ram + + # Additional disk size in GB, excluding the image's base disk. + vm_disk = var.vm_disk + + # Linux account created for SSH access. + user_login = var.vm_user_login + + # Public key installed for that account; never use a private key here. + user_public_key = var.vm_user_public_key + + # Organization IP space used by this VM. + ip_space_name = var.ip_space_name + + # true gives this VM its own external IP during deployment. + same_snat = var.vm_same_snat + + # JSON-encoded inbound port/protocol allow-list. + access_port_list = jsonencode(var.vm_access_port_list) + + # JSON-encoded source IP/CIDR allow-list; keep it as narrow as practical. + access_ip_list = jsonencode(var.vm_access_ip_list) + + # Optional marker: changing it requests redeploy on Update. + git_revision = var.git_revision + + # Optional marker: changing it requests reconcile on Update, not on Create. + reconcile_trigger = var.reconcile_trigger + + # Suspend the VM rather than fully deleting it on terraform destroy. + suspend_on_destroy = true + + # Adopt an existing same-name VM rather than failing during Create. + adopt_existing_on_create = true +}