Skip to content

Aiven vpc-id returns also project as substring causing issues with gcp vpc peering #2213

@LacikIgor

Description

@LacikIgor

What happened?

When attempting to create a vpc peering record on GCP using terraform I attempt to use the id of the generated VPC like this:

resource "google_compute_network_peering" "to_aiven" {
  name         = "peer-to-aiven"
  network      = "projects/${var.gcp_project_id}/global/networks/example-gcp-vpc"
  peer_network = "projects/aiven-prod-idcn/global/networks/aivenprod-${aiven_project_vpc.aiven_vpc.id}"

  export_custom_routes = true
  import_custom_routes = true
}

However I encounter an error - Notice that requesting vpc id from aiven_project_vpc.aiven_vpc.id also results in me receiving substring "my-project-name/" which breaks the GCP functionality and makes life difficult:

│ Error: "peer_network" ("projects/aiven-prod-idcn/global/networks/aivenprod-my-project-name/136ab947-e8e9-4c44-8697-b2979fe05e32") doesn't match regexp "projects/((?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?)))/global/networks/((?:[a-z](?:[-a-z0-9]*[a-z0-9])?))$"
│
│   with google_compute_network_peering.to_aiven,
│   on main.tf line 152, in resource "google_compute_network_peering" "to_aiven":
│  152:   peer_network = "projects/aiven-prod-idcn/global/networks/aivenprod-${aiven_project_vpc.aiven_vpc.id}"
│
╵

Full terraform script:

# Demonstrates VPC peering between Aiven and GCP
# A VM is created in a private subnet with a NAT gateway
# The VM is accessible via SSH using IAP
# VM with 

terraform {
  required_version = ">=0.13"
  required_providers {
    aiven = {
      source  = "aiven/aiven"
      version = ">=4.0.0, <5.0.0"
    }
  }
}

provider "aiven" {
  api_token = var.api_token
}


data "aiven_project" "main" {
  project = var.aiven_project_name
}

############# GCP #############
# Private subnet with NAT gateway
# Access to VM via SSH

module "gcp_vpc" {
  source  = "terraform-google-modules/network/google"
  version = "~> 11.0"

  project_id   = var.gcp_project_id
  network_name = "example-gcp-vpc"
  routing_mode = "GLOBAL"

  subnets = [
    {
      subnet_name   = "pvt-subnet-01"
      subnet_ip     = "10.10.10.0/24"
      subnet_region = "us-west1"
    },
  ]
}

resource "google_compute_firewall" "iap_ssh" {
  depends_on = [module.gcp_vpc]
  project    = var.gcp_project_id
  name       = "allow-ssh"
  network    = "example-gcp-vpc"

  allow {
    protocol = "tcp"
    ports    = ["22"]
  }
  # Allow SSH access even though instance is in a private subnet
  # See: https://cloud.google.com/iap/docs/using-tcp-forwarding 
  source_ranges = ["35.235.240.0/20"]
  target_tags   = ["iap-ssh"]
}

resource "google_compute_router" "nat_router" {
  depends_on = [module.gcp_vpc]
  name       = "example-nat-router"
  project    = var.gcp_project_id
  region     = "us-west1"
  network    = "example-gcp-vpc"
}

resource "google_compute_router_nat" "nat_gw" {
  depends_on                         = [google_compute_router.nat_router]
  name                               = "example-nat-gateway"
  project                            = var.gcp_project_id
  region                             = "us-west1"
  router                             = google_compute_router.nat_router.name
  nat_ip_allocate_option             = "AUTO_ONLY"
  source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"

  enable_endpoint_independent_mapping = true
}

resource "google_compute_instance" "peered_vm" {
  depends_on   = [module.gcp_vpc]
  name         = "example-peered-vm"
  machine_type = "e2-micro"
  zone         = "us-west1-a"
  project      = var.gcp_project_id

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    network            = "example-gcp-vpc"
    subnetwork         = "pvt-subnet-01"
    subnetwork_project = var.gcp_project_id
  }

  tags = ["iap-ssh"]

  metadata = {
    startup-script = <<-EOT
      #!/bin/bash
      sudo apt-get update
      sudo apt-get install -y postgresql-client
    EOT
  }
}

############# Aiven GCP #############
resource "aiven_project_vpc" "aiven_vpc" {
  project      = data.aiven_project.main.project
  cloud_name   = var.region_code
  network_cidr = var.network_cidr

  timeouts {
    create = "5m"
  }
}

resource "aiven_pg" "timescale_service" {
  depends_on     = [aiven_project_vpc.aiven_vpc]
  project        = data.aiven_project.main.project
  service_name   = var.postgres_service_name
  cloud_name     = var.region_code
  plan           = var.plan
  project_vpc_id = aiven_project_vpc.aiven_vpc.id

  pg_user_config {
    pg_version = var.pgversion
    variant    = "timescale"
  }

  lifecycle {
    prevent_destroy = false
  }
}

# VPC peering between Aiven and GCP
resource "aiven_gcp_vpc_peering_connection" "aiven_to_gcp_peering" {
  depends_on     = [aiven_project_vpc.aiven_vpc, module.gcp_vpc]
  vpc_id         = aiven_project_vpc.aiven_vpc.id
  gcp_project_id = var.gcp_project_id
  peer_vpc       = "example-gcp-vpc"
}

resource "google_compute_network_peering" "to_aiven" {
  name    = "peer-to-aiven"
  network = "projects/${var.gcp_project_id}/global/networks/example-gcp-vpc"
  # Split is ugly but necessary
  # See: https://github.com/aiven/terraform-provider-aiven/issues/2213
  peer_network = "projects/aiven-prod-idcn/global/networks/aivenprod-${split("/", aiven_project_vpc.aiven_vpc.id)[1]}"

  export_custom_routes = true
  import_custom_routes = true
}

Ugly solution I had to resort to

Notice, that this is an easy fix, however in my opinion vpc.id should only return the id, so that we do not need to resort to a weird split.

  peer_network = "projects/aiven-prod-idcn/global/networks/aivenprod-${split("/", aiven_project_vpc.aiven_vpc.id)[1]}"

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions