diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index 8c80949b..9b42735f 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -226,6 +226,21 @@ steps: - verify hierarchical-firewall-policy name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'cft test run TestHierarchicalFirewallPolicy --stage teardown --verbose'] +- id: converge network-connectivity-center + waitFor: + - destroy hierarchical-firewall-policy + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestNetworkConnectivityCenter --stage apply --verbose'] +- id: verify network-connectivity-center + waitFor: + - converge network-connectivity-center + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestNetworkConnectivityCenter --stage verify --verbose'] +- id: destroy network-connectivity-center + waitFor: + - verify network-connectivity-center + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestNetworkConnectivityCenter --stage teardown --verbose'] tags: - 'ci' - 'integration' diff --git a/examples/network_connectivity_center/main.tf b/examples/network_connectivity_center/main.tf new file mode 100644 index 00000000..f6345c8f --- /dev/null +++ b/examples/network_connectivity_center/main.tf @@ -0,0 +1,247 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module "network_connectivity_center" { + source = "terraform-google-modules/network/google//modules/network-connectivity-center" + project_id = var.project_id + ncc_hub_name = var.ncc_hub_name + ncc_hub_labels = { + "module" = "ncc" + } + spoke_labels = { + "created-by" = "terraform-google-ncc-example" + } + vpc_spokes = { + "vpc-1" = { + uri = module.vpc_spoke_vpc.network_id + labels = { + "spoke-type" = "vpc" + } + } + } + hybrid_spokes = { + "vpn-1" = { + type = "vpn" + uris = [for k, v in module.local_to_remote_vpn.tunnel_self_links : v] + site_to_site_data_transfer = true + location = var.vpn_region + } + } + router_appliance_spokes = { + "appliance-1" = { + instances = [ + { + virtual_machine = google_compute_instance.router_appliance_1.id + ip_address = google_compute_instance.router_appliance_1.network_interface[0].network_ip + }, + + ] + location = var.instance_region + site_to_site_data_transfer = false + } + } +} + +################################ +# VPC Spoke # +################################ +module "vpc_spoke_vpc" { + source = "terraform-google-modules/network/google" + project_id = var.project_id + network_name = var.vpc_spoke_vpc_name + routing_mode = "GLOBAL" + + subnets = [ + { + subnet_name = "vpc-spoke-subnet-01" + subnet_ip = "10.10.10.0/24" + subnet_region = "us-west1" + }, + { + subnet_name = "vpc-spoke-subnet-02" + subnet_ip = "10.10.20.0/24" + subnet_region = "us-east1" + }, + { + subnet_name = "vpc-spoke-subnet-03" + subnet_ip = "10.10.30.0/24" + subnet_region = "europe-west4" + } + ] +} + +################################ +# VPN Spoke # +################################ +# Simulates an on-prem network that will be connected over VPN +module "vpn_spoke_remote_vpc" { + source = "terraform-google-modules/network/google" + project_id = var.project_id + network_name = var.vpn_spoke_remote_vpc_name + routing_mode = "GLOBAL" + + subnets = [ + { + subnet_name = "vpn-subnet-01" + subnet_ip = "10.20.10.0/24" + subnet_region = "us-west1" + }, + { + subnet_name = "vpn-subnet-02" + subnet_ip = "10.20.20.0/24" + subnet_region = "us-east1" + }, + { + subnet_name = "vpn-subnet-03" + subnet_ip = "10.20.30.0/24" + subnet_region = "europe-west4" + } + ] +} + +module "vpn_spoke_local_vpc" { + source = "terraform-google-modules/network/google" + project_id = var.project_id + network_name = var.vpn_spoke_local_vpc_name + routing_mode = "GLOBAL" + subnets = [] +} + +module "remote_to_local_vpn" { + source = "terraform-google-modules/vpn/google//modules/vpn_ha" + version = "~> 4.0" + + project_id = var.project_id + region = var.vpn_region + network = module.vpn_spoke_remote_vpc.network_id + name = "remote-to-local" + router_asn = 64513 + peer_gcp_gateway = module.local_to_remote_vpn.self_link + tunnels = { + remote-0 = { + bgp_peer = { + address = "169.254.1.2" + asn = 64514 + } + bgp_peer_options = null + bgp_session_range = "169.254.1.1/30" + ike_version = 2 + vpn_gateway_interface = 0 + peer_external_gateway_interface = null + shared_secret = module.local_to_remote_vpn.random_secret + } + remote-1 = { + bgp_peer = { + address = "169.254.2.2" + asn = 64514 + } + bgp_peer_options = null + bgp_session_range = "169.254.2.1/30" + ike_version = 2 + vpn_gateway_interface = 1 + peer_external_gateway_interface = null + shared_secret = module.local_to_remote_vpn.random_secret + } + } +} + +module "local_to_remote_vpn" { + source = "terraform-google-modules/vpn/google//modules/vpn_ha" + version = "~> 4.0" + + project_id = var.project_id + region = var.vpn_region + network = module.vpn_spoke_local_vpc.network_id + name = "local-to-remote" + peer_gcp_gateway = module.remote_to_local_vpn.self_link + router_asn = 64514 + tunnels = { + remote-0 = { + bgp_peer = { + address = "169.254.1.1" + asn = 64513 + } + bgp_peer_options = null + bgp_session_range = "169.254.1.2/30" + ike_version = 2 + vpn_gateway_interface = 0 + peer_external_gateway_interface = null + shared_secret = "" + } + remote-1 = { + bgp_peer = { + address = "169.254.2.1" + asn = 64513 + } + bgp_peer_options = null + bgp_session_range = "169.254.2.2/30" + ike_version = 2 + vpn_gateway_interface = 1 + peer_external_gateway_interface = null + shared_secret = "" + } + } +} + + +################################ +# Router Appliance Spoke # +################################ +data "google_compute_zones" "available" { + project = var.project_id + region = var.instance_region +} + +resource "random_shuffle" "zone" { + input = data.google_compute_zones.available.names + result_count = 1 +} + +module "router_appliance_spoke_vpc" { + source = "terraform-google-modules/network/google" + project_id = var.project_id + network_name = var.router_appliance_vpc_name + routing_mode = "GLOBAL" + + subnets = [ + { + subnet_name = "router-appliance-subnet-01" + subnet_ip = "10.20.10.0/24" + subnet_region = var.instance_region + } + ] +} + +resource "google_compute_instance" "router_appliance_1" { + name = "fake-router-appliance-1" + machine_type = "e2-medium" + project = var.project_id + can_ip_forward = true + zone = random_shuffle.zone.result[0] + + boot_disk { + initialize_params { + image = "debian-cloud/debian-11" + } + } + + network_interface { + subnetwork = module.router_appliance_spoke_vpc.subnets["${var.instance_region}/router-appliance-subnet-01"].id + access_config { + network_tier = "PREMIUM" + } + } +} diff --git a/examples/network_connectivity_center/outputs.tf b/examples/network_connectivity_center/outputs.tf new file mode 100644 index 00000000..1ac306ba --- /dev/null +++ b/examples/network_connectivity_center/outputs.tf @@ -0,0 +1,46 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "project_id" { + description = "The project ID (required for testing)" + value = var.project_id +} + +output "ncc_hub_name" { + description = "Name of the NCC Hub (required for testing)" + value = element(reverse(split("/", module.network_connectivity_center.ncc_hub.name)), 0) +} + +output "vpc_spokes" { + description = "All vpc spoke objects" + value = module.network_connectivity_center.vpc_spokes +} + + +output "hybrid_spokes" { + description = "All hybrid spoke objects" + value = module.network_connectivity_center.hybrid_spokes +} + +output "router_appliance_spokes" { + description = "All router appliance spoke objects" + value = module.network_connectivity_center.router_appliance_spokes +} + +output "spokes" { + description = "All spoke objects prefixed with the type of spoke (vpc, hybrid, appliance)" + value = module.network_connectivity_center.spokes +} diff --git a/examples/network_connectivity_center/variables.tf b/examples/network_connectivity_center/variables.tf new file mode 100644 index 00000000..e677e98c --- /dev/null +++ b/examples/network_connectivity_center/variables.tf @@ -0,0 +1,59 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "The project ID to host the network in" +} + +variable "vpn_region" { + description = "The region where to deploy the VPN" + default = "europe-west4" +} + +variable "instance_region" { + description = "The region where to deploy the Router Instance in" + default = "us-central1" +} + +variable "ncc_hub_name" { + description = "The Name of the NCC Hub" + type = string + default = "ncc-hub" +} + +variable "vpc_spoke_vpc_name" { + description = "The VPC Name for the VPC Spoke" + type = string + default = "vpc-spoke" +} + +variable "vpn_spoke_local_vpc_name" { + description = "The name for the local VPC (GCP side) for the VPN Spoke" + type = string + default = "vpn-local-spoke" +} + +variable "vpn_spoke_remote_vpc_name" { + description = "The name for the remote VPC (fake on-orem) for the VPN Spoke" + type = string + default = "vpn-remote-spoke" +} + +variable "router_appliance_vpc_name" { + description = "The VPC Name for the VPC Spoke" + type = string + default = "router-appliance-spoke" +} diff --git a/examples/network_connectivity_center/versions.tf b/examples/network_connectivity_center/versions.tf new file mode 100644 index 00000000..5ebf9393 --- /dev/null +++ b/examples/network_connectivity_center/versions.tf @@ -0,0 +1,27 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">=0.13.0" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.40.0" + + } + } +} diff --git a/modules/network-connectivity-center/README.md b/modules/network-connectivity-center/README.md new file mode 100644 index 00000000..3b1e5b6b --- /dev/null +++ b/modules/network-connectivity-center/README.md @@ -0,0 +1,45 @@ +# Terraform Network Connectivity Center Module + +This submodule is part of the the `terraform-google-network` module. It creates a Network Connectivity Center Hub and attaches spokes. + +## Usage + +Basic usage of this submodule is as follows: + +```hcl +module "ncc" { + source = "terraform-google-modules/network/google//modules/network-connectivity-center" + version = "~> 9.0.0" + + project_id = "" +} +``` + +An extensive example that also contains the creation and attachment of multiple spokes can be found in [examples/network-connectivity-center](../../examples/network_connectivity_center/) + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| export\_psc | Whether Private Service Connect transitivity is enabled for the hub | `bool` | `false` | no | +| hybrid\_spokes | VLAN attachments and VPN Tunnels that are associated with the spoke. Type must be one of `interconnect` and `vpn`. |
map(object({
location = string
uris = set(string)
site_to_site_data_transfer = optional(bool, false)
type = string
description = optional(string)
labels = optional(map(string))
}))
| `{}` | no | +| ncc\_hub\_description | The description of the NCC Hub | `string` | `null` | no | +| ncc\_hub\_labels | These labels will be added the NCC hub | `map(string)` | `{}` | no | +| ncc\_hub\_name | The Name of the NCC Hub | `string` | n/a | yes | +| project\_id | Project ID of the project that holds the network. | `string` | n/a | yes | +| router\_appliance\_spokes | Router appliance instances that are associated with the spoke. |
map(object({
instances = set(object({
virtual_machine = string
ip_address = string
}))
location = string
site_to_site_data_transfer = optional(bool, false)
description = optional(string)
labels = optional(map(string))
}))
| `{}` | no | +| spoke\_labels | These labels will be added to all NCC spokes | `map(string)` | `{}` | no | +| vpc\_spokes | VPC network that is associated with the spoke |
map(object({
uri = string
exclude_export_ranges = optional(set(string), [])
include_export_ranges = optional(set(string), [])
description = optional(string)
labels = optional(map(string))
}))
| `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| hybrid\_spokes | All hybrid spoke objects | +| ncc\_hub | The NCC Hub object | +| router\_appliance\_spokes | All router appliance spoke objects | +| spokes | All spoke objects prefixed with the type of spoke (vpc, hybrid, appliance) | +| vpc\_spokes | All vpc spoke objects | + + diff --git a/modules/network-connectivity-center/main.tf b/modules/network-connectivity-center/main.tf new file mode 100644 index 00000000..7dc0a7bc --- /dev/null +++ b/modules/network-connectivity-center/main.tf @@ -0,0 +1,114 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + vpc_spokes = { + for k, v in google_network_connectivity_spoke.vpc_spoke : + k => v + } + hybrid_spokes = { + for k, v in google_network_connectivity_spoke.hybrid_spoke : + k => v + } + router_appliance_spokes = { + for k, v in google_network_connectivity_spoke.router_appliance_spoke : + k => v + } +} + +resource "google_network_connectivity_hub" "hub" { + name = var.ncc_hub_name + project = var.project_id + description = var.ncc_hub_description + export_psc = var.export_psc + labels = var.ncc_hub_labels +} + + +resource "google_network_connectivity_spoke" "vpc_spoke" { + for_each = var.vpc_spokes + project = var.project_id + name = each.key + location = "global" + description = each.value.description + hub = google_network_connectivity_hub.hub.id + labels = merge(var.spoke_labels, each.value.labels) + + linked_vpc_network { + uri = each.value.uri + exclude_export_ranges = each.value.exclude_export_ranges + include_export_ranges = each.value.include_export_ranges + } +} + +resource "google_network_connectivity_spoke" "hybrid_spoke" { + for_each = var.hybrid_spokes + project = var.project_id + name = each.key + location = each.value.location + description = each.value.description + hub = google_network_connectivity_hub.hub.id + labels = merge(var.spoke_labels, each.value.labels) + + dynamic "linked_interconnect_attachments" { + for_each = each.value.type == "interconnect" ? [1] : [] + content { + uris = each.value.uris + site_to_site_data_transfer = each.value.site_to_site_data_transfer + } + } + + dynamic "linked_vpn_tunnels" { + for_each = each.value.type == "vpn" ? [1] : [] + content { + uris = each.value.uris + site_to_site_data_transfer = each.value.site_to_site_data_transfer + } + } + + # TODO: gleichda remove once b/369823133 is fixed + depends_on = [ + google_network_connectivity_spoke.vpc_spoke + ] +} + +resource "google_network_connectivity_spoke" "router_appliance_spoke" { + for_each = var.router_appliance_spokes + project = var.project_id + name = each.key + location = each.value.location + description = each.value.description + hub = google_network_connectivity_hub.hub.id + labels = merge(var.spoke_labels, each.value.labels) + + linked_router_appliance_instances { + dynamic "instances" { + for_each = each.value.instances + iterator = instance_list + content { + virtual_machine = instance_list.value.virtual_machine + ip_address = instance_list.value.ip_address + } + } + site_to_site_data_transfer = each.value.site_to_site_data_transfer + + } + + # TODO: gleichda remove once b/369823133 is fixed + depends_on = [ + google_network_connectivity_spoke.hybrid_spoke + ] +} diff --git a/modules/network-connectivity-center/outputs.tf b/modules/network-connectivity-center/outputs.tf new file mode 100644 index 00000000..3b306adf --- /dev/null +++ b/modules/network-connectivity-center/outputs.tf @@ -0,0 +1,54 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +output "ncc_hub" { + description = "The NCC Hub object" + value = google_network_connectivity_hub.hub +} + +output "vpc_spokes" { + description = "All vpc spoke objects" + value = local.vpc_spokes +} + + +output "hybrid_spokes" { + description = "All hybrid spoke objects" + value = local.hybrid_spokes +} + +output "router_appliance_spokes" { + description = "All router appliance spoke objects" + value = local.router_appliance_spokes +} + +output "spokes" { + description = "All spoke objects prefixed with the type of spoke (vpc, hybrid, appliance)" + value = flatten([ + { + for k, v in local.vpc_spokes : + "vpc/${k}" => v + }, + { + for k, v in local.hybrid_spokes : + "hybrid/${k}" => v + }, + { + for k, v in local.router_appliance_spokes : + "appliance/${k}" => v + }, + ]) +} diff --git a/modules/network-connectivity-center/variables.tf b/modules/network-connectivity-center/variables.tf new file mode 100644 index 00000000..26612b3b --- /dev/null +++ b/modules/network-connectivity-center/variables.tf @@ -0,0 +1,88 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + description = "Project ID of the project that holds the network." + type = string +} + +variable "ncc_hub_name" { + description = "The Name of the NCC Hub" + type = string +} + +variable "ncc_hub_description" { + description = "The description of the NCC Hub" + type = string + default = null +} +variable "ncc_hub_labels" { + description = "These labels will be added the NCC hub" + type = map(string) + default = {} +} + +variable "export_psc" { + description = "Whether Private Service Connect transitivity is enabled for the hub" + type = bool + default = false +} + +variable "vpc_spokes" { + description = "VPC network that is associated with the spoke" + type = map(object({ + uri = string + exclude_export_ranges = optional(set(string), []) + include_export_ranges = optional(set(string), []) + description = optional(string) + labels = optional(map(string)) + })) + default = {} +} + +variable "hybrid_spokes" { + description = "VLAN attachments and VPN Tunnels that are associated with the spoke. Type must be one of `interconnect` and `vpn`." + type = map(object({ + location = string + uris = set(string) + site_to_site_data_transfer = optional(bool, false) + type = string + description = optional(string) + labels = optional(map(string)) + })) + default = {} +} + +variable "router_appliance_spokes" { + description = "Router appliance instances that are associated with the spoke." + type = map(object({ + instances = set(object({ + virtual_machine = string + ip_address = string + })) + location = string + site_to_site_data_transfer = optional(bool, false) + description = optional(string) + labels = optional(map(string)) + })) + default = {} +} + +variable "spoke_labels" { + description = "These labels will be added to all NCC spokes" + type = map(string) + default = {} +} diff --git a/modules/network-connectivity-center/versions.tf b/modules/network-connectivity-center/versions.tf new file mode 100644 index 00000000..de82dd4a --- /dev/null +++ b/modules/network-connectivity-center/versions.tf @@ -0,0 +1,30 @@ +/** + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = ">= 1.3.0" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 6.2.0, < 7" + + } + } + provider_meta "google" { + module_name = "blueprints/terraform/terraform-google-network:network-connectivity-center/v9.2.0" + } +} diff --git a/test/integration/network_connectivity_center/network_connectivity_center_test.go b/test/integration/network_connectivity_center/network_connectivity_center_test.go new file mode 100644 index 00000000..757727c2 --- /dev/null +++ b/test/integration/network_connectivity_center/network_connectivity_center_test.go @@ -0,0 +1,44 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ncc + +import ( + // "strings" + + "testing" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" + "github.com/stretchr/testify/assert" +) + +func TestNetworkConnectivityCenter(t *testing.T) { + net := tft.NewTFBlueprintTest(t) + net.DefineVerify( + func(assert *assert.Assertions) { + net.DefaultVerify(assert) + projectID := net.GetStringOutput("project_id") + nccHubName := net.GetStringOutput("ncc_hub_name") + expectedNccSpokesCount := 3 + + op := gcloud.Run(t, "network-connectivity hubs describe ", gcloud.WithCommonArgs([]string{nccHubName, "--project", projectID, "--format", "json"})) + nccSpokeStateCount := op.Get("spokeSummary.spokeStateCounts").Array() + assert.Equal(1, len(nccSpokeStateCount), "should have spokes in one State") + assert.Equal("ACTIVE", nccSpokeStateCount[0].Get("state").String(), "should have only active spokes") + assert.Equal(int64(expectedNccSpokesCount), nccSpokeStateCount[0].Get("count").Int(), "should have exactly 3 spokes") + assert.Equal(expectedNccSpokesCount, len(op.Get("spokeSummary.spokeTypeCounts").Array()), "should have 3 different spoke types") + }) + net.Test() +} diff --git a/test/setup/iam.tf b/test/setup/iam.tf index c13c61d3..b9f270c6 100644 --- a/test/setup/iam.tf +++ b/test/setup/iam.tf @@ -16,6 +16,7 @@ locals { int_required_roles = [ + "roles/compute.instanceAdmin", "roles/compute.networkAdmin", "roles/compute.securityAdmin", "roles/iam.serviceAccountUser", @@ -25,6 +26,7 @@ locals { "roles/resourcemanager.tagAdmin", "roles/iam.serviceAccountAdmin", "roles/compute.orgFirewallPolicyAdmin", + "roles/networkconnectivity.hubAdmin", ] } diff --git a/test/setup/main.tf b/test/setup/main.tf index 79cbb95d..59d1825e 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -53,6 +53,7 @@ module "project" { "vpcaccess.googleapis.com", "dns.googleapis.com", "networksecurity.googleapis.com", + "networkconnectivity.googleapis.com", "iam.googleapis.com", ] }