mvm-s3 is a separate VK Cloud project whose admin pre-created two private
networks/subnets with a known IP per router. Unify project-managed
(private_network_cidrs, IPAM-assigned) and externally-owned (router_networks,
fixed-IP) private interfaces into one local.router_interfaces so both share
the existing port/dynamic-network mechanism instead of duplicating it.
Switch from implicit *.auto.tfvars loading to explicit -var-file per
environment (now two share this terraform/ directory) plus a dedicated
Terraform workspace for mvm-s3, so PROD's state and credentials are never
touched by mvm-s3 applies.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GHfG9FgpMrGdrvC1QUewTw
Horizontal scale-out of the deployed group per user request - all other
requirements unchanged. terraform apply added only router4 and its 2
private ports (3 added, 0 changed, 0 destroyed); the existing 3 routers
were untouched. Deployment summary updated with router4's addresses.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r
Confirmed working against a real VK Cloud PROD deployment (3 routers,
19 resources, apply succeeded end to end). Fixes found along the way:
- provider "vkcs" was never configured (versions.tf) - username/password/
project_id/region were declared but wired to nothing; added auth_url and
user_domain_name to complete it.
- Nova keypairs are per-user, not per-project - added an optional
vkcs_compute_keypair resource (var.ssh_public_key) so Terraform can
register a keypair under the deploying service account itself.
- router_priv_port used a hand-computed fixed_ip offset that collided with
VKCS's own auto-created service ports on each network (observed: a
"network:dns" port) - now left unset so Neutron's IPAM auto-assigns,
which is collision-free by construction.
- vkcs_compute_instance set image_id at the top level while also booting
from a volume via block_device - the provider docs say not to do this;
Nova echoes back a sentinel string for image_id on a volume-booted
server, which Terraform read as drift on a ForceNew attribute and
wanted to destroy+recreate every already-created instance on every
subsequent plan.
- private_network_cidrs bumped from /29 to /28 - too tight once the
platform's own reserved ports are accounted for.
Also removed the priv_srv_01/02/03 demo instances and the LAN network/
security group only they used - this deployment provisions router VMs
only, confirmed with the user.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r
private_supernet/private_subnet_prefix_length/private_interface_count
(which auto-derived per-router-per-role micro-subnets via cidrsubnet())
are replaced by a single required variable, private_network_cidrs: one
CIDR per shared private network that router VMs get an interface into,
supplied explicitly by the admin - no auto-carving. Each router gets its
own port/IP inside every listed network (cidrhost(cidr, router_index+2)),
closer to the original lan_net design but generalized to N networks and
N routers. network-init.sh.tpl needed no changes - it already matches
interfaces by CIDR membership regardless of whether the CIDR is shared.
Also fixes a testing gap found along the way: `terraform validate` does
not enforce variable validation{} blocks for externally-supplied values
in this terraform version - only `plan`/`apply` do. The test suite now
exercises those validations for real via `terraform plan` against an
isolated, provider-free copy of variables.tf.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r
Terraform now provisions router_count IaaS Router VMs (default 2, no
longer hardcoded to router1/router2), each with 1 public +
private_interface_count isolated private interfaces (no shared LAN or
VRRP between routers). Both counts scale via Terraform variables and
TF_VAR_* environment variables. The post-install script became a
Terraform template that matches interfaces to their expected subnet by
CIDR instead of a fragile "first private IP" heuristic.
Added an offline pytest suite (terraform/tests/) that checks the
delivery's internal consistency and runs real terraform init/validate
against the actual vkcs provider schema via a project-local filesystem
mirror (provider binary fetched from its GitHub releases, bypassing the
region-blocked HashiCorp registry) - no cloud credentials or API calls
involved. terraform/versions.tf now declares the previously-missing
required_providers block.
Ansible (inventory.ini, base/frr_router/keepalived roles) still assumes
the old 2-router/2-NIC/VRRP topology and is not yet adapted - documented
as a follow-up, not addressed here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hXR2ftXZZhJ4Y3XuSoR8r