Skip to content

feat(vpnaas): Neutron VPNaaS family (service, IKE/IPsec policies, endpoint group, site connection) - #21

Merged
PF9-pushkar merged 1 commit into
mainfrom
feat/vpnaas
Jul 12, 2026
Merged

feat(vpnaas): Neutron VPNaaS family (service, IKE/IPsec policies, endpoint group, site connection)#21
PF9-pushkar merged 1 commit into
mainfrom
feat/vpnaas

Conversation

@PF9-pushkar

Copy link
Copy Markdown
Collaborator

Summary

Adds the VPNaaS family (Phase 3, final family), ported from terraform-provider-openstack v3.4.0. New internal/services/vpnaas package reusing NetworkV2Client (VPNaaS is a Neutron extension — no new client).

Resource Purpose
pcd_vpnaas_service VPN endpoint attached to a router
pcd_vpnaas_ike_policy IKE policy (nested lifetime)
pcd_vpnaas_ipsec_policy IPsec policy (nested lifetime)
pcd_vpnaas_endpoint_group local subnets / peer CIDRs
pcd_vpnaas_site_connection site-to-site connection (nested dpd, sensitive psk)

Design

  • Nested blocks (lifetime, dpd) are SingleNestedAttribute (Optional+Computed) with UseStateForUnknown on both the whole object and each sub-field — a partially-specified block (e.g. dpd = { action = "restart" }) doesn't churn on the omitted sub-fields, and an omitted block takes the server default. peer_cidrs is an Optional+Computed list.
  • Server-populated fields are Optional+Computed (or have a default). Enum fields with an upstream default (auth_algorithm, encryption_algorithm, pfs, ike_version, phase1_negotiation_mode) get that default; the rest are server-assigned.
  • Async delete: the service and site connection wait for the object to 404 after delete, so a dependent router/subnet can be torn down in the same apply. Policies and endpoint groups delete synchronously.
  • Import by object UUID; ForceNew on the immutable references (router_id, the IKE/IPsec/VPN policy IDs, endpoint type/endpoints, tenant_id).

Notes

  • Matches upstream field-for-field except the value_specs escape hatch (unused anywhere in this port; a documented deferral).
  • Avoids two upstream bugs found during research: the phase_1_negotiation_mode update-key typo (updates silently dropped) and the peer_cidrs.([]string) cast panic on update.
  • Fixed a self-caught issue before review: nested-attribute examples must use HCL = { ... } assignment (not block { ... }) syntax for a SingleNestedAttribute.

Adversarial review

A review workflow (3 finder dimensions — state-consistency incl. nested-object apply-consistency, gophercloud API usage, lifecycle/delete/import/registration — each finding adversarially verified against Terraform core + gophercloud source) returned 0 confirmed findings. The one candidate (psk read back from the server) was refuted: Neutron returns the PSK verbatim, so reading it back is safe and detects out-of-band drift.

Testing

  • go build, go vet, gofmt, golangci-lint — clean (0 issues); unit tests pass; terraform fmt clean; docs regenerate with the "VPN" subcategory.
  • Full-tree acceptance test (TestAccVPNaaS_tree): service + IKE/IPsec policies + local/peer endpoint groups + site connection, verify via API, rename, import. Not run live this session (CE lab credentials unavailable; needs the Neutron vpnaas extension enabled); tracked PENDING in DECISIONS.md.

Add a new internal/services/vpnaas package (reusing NetworkV2Client, since
VPNaaS is a Neutron extension) with the site-to-site IPsec VPN resources:

- pcd_vpnaas_service         (VPN endpoint on a router)
- pcd_vpnaas_ike_policy      (nested lifetime block)
- pcd_vpnaas_ipsec_policy    (nested lifetime block)
- pcd_vpnaas_endpoint_group  (local subnets / peer CIDRs)
- pcd_vpnaas_site_connection (nested dpd block, sensitive psk)

Design:

- lifetime and dpd are SingleNestedAttribute (Optional+Computed) with
  UseStateForUnknown on both the whole object and each sub-field, so a
  partially-specified block does not churn and omitted blocks take the server
  default. peer_cidrs is an Optional+Computed list.
- Every server-populated field is Optional+Computed (or has a default); the
  enum fields with an upstream default (auth/encryption/pfs/ike_version/
  phase1_negotiation_mode) get that default, the rest are server-assigned.
- The VPN service and site connection wait for the object to 404 after delete
  (asynchronous teardown), so a dependent router/subnet can be torn down in the
  same apply. Policies and endpoint groups delete synchronously.
- Import by the object UUID; ForceNew on the immutable references
  (router_id, ike/ipsec/vpn policy ids, endpoint type/endpoints, tenant_id).

Templates gain a "vpnaas" -> "VPN" documentation subcategory. Matches upstream
field-for-field except the value_specs escape hatch (not used anywhere in this
port). Avoids two upstream bugs: the phase_1_negotiation_mode update-key typo
and the peer_cidrs []string cast panic.

Includes a full-tree acceptance test (service + policies + endpoint groups +
site connection + rename + import), examples, and CHANGELOG/DECISIONS entries.
@PF9-pushkar
PF9-pushkar merged commit 9493c44 into main Jul 12, 2026
4 checks passed
@PF9-pushkar
PF9-pushkar deleted the feat/vpnaas branch July 12, 2026 19:46
PF9-pushkar added a commit that referenced this pull request Jul 14, 2026
feat(vpnaas): Neutron VPNaaS family (service, IKE/IPsec policies, endpoint group, site connection)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant