# Пайплайн: vDC → Edge → внешние IP → SNAT > Проверено на dev-стенде 2026-09-24 (провайдер `2.0.20`): один `apply` собирает всю цепочку, > повторный `plan` не показывает изменений, `destroy` проходит в обратном порядке. ## Что делает пайплайн Собирает сетевую основу под нагрузку: виртуальный датацентр, периметровый шлюз, внешние IP на организации и SNAT на шлюзе — **без ручных операций в ЛК после создания организации**. **Кластер Штурвал в этот пайплайн не входит** — он разворачивается очень долго, это отдельный шаг. ## Что вне Terraform (создаётся один раз вручную) **Организация в Cloud Director** — одна на ресурсный realm, создать вторую нельзя. В конфиге она адресуется по UUID (`org_uid`), а её внешние IP выделяются уже Terraform-ресурсом. ## Порядок и почему он такой | # | Ресурс | Что создаёт | |---|---|---| | 1 | `nubes_vc_vdc` | виртуальный датацентр | | 2 | `nubes_vc_nsxt` | сетевой шлюз периметра (Edge), ALB/AVI | | 3 | `nubes_vc_org_ip_allocation` | внешние IP на организации (`vIPConfigure`) | | 4 | `nubes_vc_nsxt_snat` | SNAT на шлюзе (`ipSpaceName`) | Порядок обязателен: шаги 3 и 4 — операции `modify`, а платформа строит список доступных `ipSpace` из состояния `job.vcd.networkProvider` / `job.vcd.providerGateway`, то есть **требует уже созданные vDC и Edge**. В инструкции к операции это записано прямо: «предварительно необходимо создать Виртуальный датацентр (VDC), потом Сетевой шлюз периметра (Edge Gateway)». Если открыть `modify` на организации без vDC/Edge, список значений падает с ошибкой `Can't cast Complex Object Type Struct to String`. ## Пример конфигурации ```hcl resource "nubes_vc_vdc" "vdc" { resource_name = "fullpipe-vdc" organization_uid = var.organization # имя или UUID существующей организации network_provider = "snb1" # из ЛК provider_vdc = "Intel Broadwell 2.4" storage_config = jsonencode([{ name = "SATA", size = "200" }]) suspend_on_destroy = true } resource "nubes_vc_nsxt" "edge" { resource_name = "fullpipe-edge" vdc_type = "vdc" vdc_uid = nubes_vc_vdc.vdc.id # Edge создаётся только после vDC need_enable_avi = true virtual_services_count = 3 # Штурвалу нужно ≥ 3 routed_net_configuration = { ip_addr_pool = "10.10.102.0/24" main_dns = "81.22.46.22" second_dns = "185.247.187.77" } } # Внешние IP на организации — только после создания Edge resource "nubes_vc_org_ip_allocation" "org_ip" { org_uid = var.org_uid # UUID организации vip_configure = jsonencode([ { name = "internet-ipv4-v1", count = "3" } ]) depends_on = [nubes_vc_nsxt.edge] } # SNAT на шлюзе этим ipSpace resource "nubes_vc_nsxt_snat" "snat" { nsxt_uid = nubes_vc_nsxt.edge.id ip_space_name = "internet-ipv4-v1" depends_on = [nubes_vc_org_ip_allocation.org_ip] } ``` Порядок ключей в `vip_configure` и его форматирование значения не имеют — сравнение смысловое. ## Готовые файлы примеров Комплект `.tf`-файлов (vDC, Edge, аллокация IP, SNAT) лежит в отдельном репозитории примеров: **** - каталог `modify_resources/` — ресурсы-модификаторы (аллокация IP на организации + SNAT); - `terraform.tfvars.example` — шаблон переменных (реальный `terraform.tfvars` с токеном нигде не публикуется). Клонирование целиком: ```bash git clone https://gitea.services.ngcloud.ru/Nail/tf_examples.git ``` ## Значения, которые берутся из ЛК | Параметр | Где смотреть | |---|---| | `organization_uid` / `org_uid` | карточка услуги «Организация в Cloud Director» | | `network_provider`, `provider_vdc` | страница vDC | | `storage_config` (имена политик) | дисковые политики ресурсного пула (`SATA`, `SSD`) | | `ip_space_name` | список ipSpace организации (доступен после создания vDC и Edge) | ## Удаление `terraform destroy` идёт в обратном порядке и сам приводит систему в исходное состояние: | # | Ресурс | Обратная операция | |---|---|---| | 1 | `nubes_vc_nsxt_snat` | `modify` с `ipSpaceName = "no-needed"` (SNAT выключается) | | 2 | `nubes_vc_org_ip_allocation` | `modify` с `count = "0"` (квота IP обнуляется) | | 3 | `nubes_vc_nsxt` | удаление шлюза | | 4 | `nubes_vc_vdc` | удаление vDC | Организацию удаление не затрагивает. Если снимать SNAT или квоту не нужно — у ресурсов есть `keep_on_destroy = true`. ## Что подтверждено живым прогоном (dev, 2026-09-24) - вся цепочка поднимается **одним `apply`**; - повторный `plan` не требует изменений; - после apply в API: у организации `vIPConfigure: [{"name":"internet-ipv4-v1","count":"3"}]`, у шлюза `ipSpaceName: "internet-ipv4-v1"`, при этом `needEnableAVI` и `virtualServicesCount` не затираются (SNAT-модификация отправляет только своё поле); - `destroy` выключает SNAT и обнуляет квоту, орг остаётся живой.