diff --git a/overrides/terraform/resource_override.rb b/overrides/terraform/resource_override.rb index 285d6f675f69..316af5d576c9 100644 --- a/overrides/terraform/resource_override.rb +++ b/overrides/terraform/resource_override.rb @@ -24,6 +24,13 @@ module Terraform class ResourceOverride < Overrides::ResourceOverride def self.attributes [ + # If non-empty, overrides the full filename prefix + # i.e. google/resource_product_{{resource_filename_override}}.go + # i.e. google/resource_product_{{resource_filename_override}}_test.go + # Note this doesn't override the actual resource name + # use :legacy_name instead. + :filename_override, + # If non-empty, overrides the full given resource name. # i.e. 'google_project' for resourcemanager.Project # Use Provider::Terraform::Config.legacy_name to override just @@ -92,6 +99,7 @@ def validate @examples ||= [] + check :filename_override, type: String check :legacy_name, type: String check :id_format, type: String check :examples, item_type: Provider::Terraform::Examples, type: Array, default: [] diff --git a/products/networkmanagement/api.yaml b/products/networkmanagement/api.yaml new file mode 100644 index 000000000000..7c1781b9b9d8 --- /dev/null +++ b/products/networkmanagement/api.yaml @@ -0,0 +1,212 @@ +# Copyright 2020 Google Inc. +# 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. + +--- !ruby/object:Api::Product +name: NetworkManagement +display_name: NetworkManagement +scopes: + - https://www.googleapis.com/auth/cloud-platform +versions: + - !ruby/object:Api::Product::Version + name: ga + base_url: https://networkmanagement.googleapis.com/v1/ +apis_required: + - !ruby/object:Api::Product::ApiReference + name: Network Management API + url: https://console.cloud.google.com/apis/library/networkmanagement.googleapis.com/ +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' +objects: + - !ruby/object:Api::Resource + name: 'ConnectivityTest' + base_url: projects/{{project}}/locations/global/connectivityTests + create_url: projects/{{project}}/locations/global/connectivityTests?testId={{name}} + update_verb: :PATCH + update_mask: true + description: | + A connectivity test are a static analysis of your resource configurations + that enables you to evaluate connectivity to and from Google Cloud + resources in your Virtual Private Cloud (VPC) network. + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Official Documentation': + 'https://cloud.google.com/network-intelligence-center/docs' + api: 'https://cloud.google.com/network-intelligence-center/docs/connectivity-tests/reference/networkmanagement/rest/v1/projects.locations.global.connectivityTests' + iam_policy: !ruby/object:Api::Resource::IamPolicy + exclude: true + method_name_separator: ':' + parent_resource_attribute: 'connectivityTest' + import_format: ["projects/{{project}}/locations/global/connectivityTests/{{connectivityTest}}", "{{connectivityTest}}"] + properties: + - !ruby/object:Api::Type::String + name: name + description: |- + Unique name for the connectivity test. + required: true + input: true + - !ruby/object:Api::Type::String + name: description + description: |- + The user-supplied description of the Connectivity Test. + Maximum of 512 characters. + - !ruby/object:Api::Type::NestedObject + name: 'source' + required: true + description: | + Required. Source specification of the Connectivity Test. + + You can use a combination of source IP address, virtual machine + (VM) instance, or Compute Engine network to uniquely identify the + source location. + + Examples: If the source IP address is an internal IP address within + a Google Cloud Virtual Private Cloud (VPC) network, then you must + also specify the VPC network. Otherwise, specify the VM instance, + which already contains its internal IP address and VPC network + information. + + If the source of the test is within an on-premises network, then + you must provide the destination VPC network. + + If the source endpoint is a Compute Engine VM instance with multiple + network interfaces, the instance itself is not sufficient to + identify the endpoint. So, you must also specify the source IP + address or VPC network. + + A reachability analysis proceeds even if the source location is + ambiguous. However, the test result may include endpoints that + you don't intend to test. + properties: + - !ruby/object:Api::Type::String + name: ipAddress + description: |- + The IP address of the endpoint, which can be an external or + internal IP. An IPv6 address is only allowed when the test's + destination is a global load balancer VIP. + - !ruby/object:Api::Type::Integer + name: port + description: |- + The IP protocol port of the endpoint. Only applicable when + protocol is TCP or UDP. + - !ruby/object:Api::Type::String + name: instance + description: |- + A Compute Engine instance URI. + - !ruby/object:Api::Type::String + name: network + description: |- + A Compute Engine network URI. + - !ruby/object:Api::Type::Enum + name: networkType + description: |- + Type of the network where the endpoint is located. + values: + - :GCP_NETWORK + - :NON_GCP_NETWORK + - !ruby/object:Api::Type::String + name: projectId + description: |- + Project ID where the endpoint is located. The Project ID can be + derived from the URI if you provide a VM instance or network URI. + The following are two cases where you must provide the project ID: + + 1. Only the IP address is specified, and the IP address is + within a GCP project. + 2. When you are using Shared VPC and the IP address + that you provide is from the service project. In this case, + the network that the IP address resides in is defined in the + host project. + - !ruby/object:Api::Type::NestedObject + name: 'destination' + required: true + description: | + Required. Destination specification of the Connectivity Test. + + You can use a combination of destination IP address, Compute + Engine VM instance, or VPC network to uniquely identify the + destination location. + + Even if the destination IP address is not unique, the source IP + location is unique. Usually, the analysis can infer the destination + endpoint from route information. + + If the destination you specify is a VM instance and the instance has + multiple network interfaces, then you must also specify either a + destination IP address or VPC network to identify the destination + interface. + + A reachability analysis proceeds even if the destination location + is ambiguous. However, the result can include endpoints that you + don't intend to test. + properties: + - !ruby/object:Api::Type::String + name: ipAddress + description: |- + The IP address of the endpoint, which can be an external or + internal IP. An IPv6 address is only allowed when the test's + destination is a global load balancer VIP. + - !ruby/object:Api::Type::Integer + name: port + description: |- + The IP protocol port of the endpoint. Only applicable when + protocol is TCP or UDP. + - !ruby/object:Api::Type::String + name: instance + description: |- + A Compute Engine instance URI. + - !ruby/object:Api::Type::String + name: network + description: |- + A Compute Engine network URI. + - !ruby/object:Api::Type::String + name: projectId + description: |- + Project ID where the endpoint is located. The Project ID can be + derived from the URI if you provide a VM instance or network URI. + The following are two cases where you must provide the project ID: + 1. Only the IP address is specified, and the IP address is within + a GCP project. 2. When you are using Shared VPC and the IP address + that you provide is from the service project. In this case, the + network that the IP address resides in is defined in the host + project. + - !ruby/object:Api::Type::String + name: protocol + description: |- + IP Protocol of the test. When not provided, "TCP" is assumed. + default_value: "TCP" + - !ruby/object:Api::Type::Array + name: relatedProjects + description: |- + Other projects that may be relevant for reachability analysis. + This is applicable to scenarios where a test can cross project + boundaries. + item_type: Api::Type::String + - !ruby/object:Api::Type::KeyValuePairs + name: 'labels' + description: | + Resource labels to represent user-provided metadata. diff --git a/products/networkmanagement/terraform.yaml b/products/networkmanagement/terraform.yaml new file mode 100644 index 000000000000..2954652b4638 --- /dev/null +++ b/products/networkmanagement/terraform.yaml @@ -0,0 +1,55 @@ +# Copyright 2019 Google Inc. +# 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. + +--- !ruby/object:Provider::Terraform::Config +overrides: !ruby/object:Overrides::ResourceOverrides + ConnectivityTest: !ruby/object:Overrides::Terraform::ResourceOverride + filename_override: 'connectivity_test_resource' + id_format: projects/{{project}}/locations/global/connectivityTests/{{name}} + autogen_async: true + examples: + - !ruby/object:Provider::Terraform::Examples + name: "network_management_connectivity_test_instances" + primary_resource_id: "instance-test" + vars: + primary_resource_name: "conn-test-instances" + network_name: "conn-test-net" + source_instance: "source-vm" + dest_instance: "dest-vm" + - !ruby/object:Provider::Terraform::Examples + name: "network_management_connectivity_test_addresses" + primary_resource_id: "address-test" + vars: + primary_resource_name: "conn-test-addr" + network: "connectivity-vpc" + source_addr: "src-addr" + dest_addr: "dest-addr" + properties: + name: !ruby/object:Overrides::Terraform::PropertyOverride + custom_expand: 'templates/terraform/custom_expand/network_management_connectivity_test_name.go.erb' + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' + source: !ruby/object:Overrides::Terraform::PropertyOverride + update_mask_fields: + - "source.ipAddress" + - "source.port" + - "source.instance" + - "source.network" + - "source.networkType" + - "source.projectId" + destination: !ruby/object:Overrides::Terraform::PropertyOverride + update_mask_fields: + - "destination.ipAddress" + - "destination.port" + - "destination.instance" + - "destination.network" + - "destination.projectId" diff --git a/provider/terraform.rb b/provider/terraform.rb index d0338a65ee3c..671c9466b461 100644 --- a/provider/terraform.rb +++ b/provider/terraform.rb @@ -1,4 +1,4 @@ -# Copyright 2017 Google Inc. +# Copyright 2020 Google Inc. # 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 @@ -179,7 +179,7 @@ def folder_name(version) # per resource. The resource.erb template forms the basis of a single # GCP Resource on Terraform. def generate_resource(pwd, data) - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = data.product.name.underscore FileUtils.mkpath folder_name(data.version) unless Dir.exist?(folder_name(data.version)) @@ -194,7 +194,7 @@ def generate_documentation(pwd, data) target_folder = data.output_folder target_folder = File.join(target_folder, 'website', 'docs', 'r') FileUtils.mkpath target_folder - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = @config.legacy_name || data.product.name.underscore filepath = @@ -211,7 +211,7 @@ def generate_resource_tests(pwd, data) end .empty? - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = data.product.name.underscore data.product = data.product.name @@ -231,7 +231,7 @@ def generate_resource_sweepers(pwd, data) data.object.custom_code.pre_delete || data.object.skip_delete - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = data.product.name.underscore data.product = data.product.name @@ -261,7 +261,7 @@ def generate_operation(pwd, output_folder, _types) # Generate the IAM policy for this object. This is used to query and test # IAM policies separately from the resource itself def generate_iam_policy(pwd, data) - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = data.product.name.underscore FileUtils.mkpath folder_name(data.version) unless Dir.exist?(folder_name(data.version)) @@ -287,7 +287,7 @@ def generate_iam_documentation(pwd, data) target_folder = data.output_folder target_folder = File.join(target_folder, 'website', 'docs', 'r') FileUtils.mkpath target_folder - name = data.object.name.underscore + name = data.object.filename_override || data.object.name.underscore product_name = @config.legacy_name || data.product.name.underscore filepath = diff --git a/templates/terraform/custom_expand/network_management_connectivity_test_name.go.erb b/templates/terraform/custom_expand/network_management_connectivity_test_name.go.erb new file mode 100644 index 000000000000..2fd5a83ffe4e --- /dev/null +++ b/templates/terraform/custom_expand/network_management_connectivity_test_name.go.erb @@ -0,0 +1,22 @@ +<%- # the license inside this block applies to this file + # Copyright 2020 Google Inc. + # 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. +-%> +func expand<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + // projects/X/tests/Y - note not "connectivityTests" + f, err := parseGlobalFieldValue("tests", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for zone: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/templates/terraform/examples/network_management_connectivity_test_addresses.tf.erb b/templates/terraform/examples/network_management_connectivity_test_addresses.tf.erb new file mode 100644 index 000000000000..f67260dd4f94 --- /dev/null +++ b/templates/terraform/examples/network_management_connectivity_test_addresses.tf.erb @@ -0,0 +1,44 @@ +resource "google_network_management_connectivity_test" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['primary_resource_name'] %>" + source { + ip_address = google_compute_address.source-addr.address + project_id = google_compute_address.source-addr.project + network = google_compute_network.vpc.id + network_type = "GCP_NETWORK" + } + + destination { + ip_address = google_compute_address.dest-addr.address + project_id = google_compute_address.dest-addr.project + network = google_compute_network.vpc.id + } + + protocol = "UDP" +} + +resource "google_compute_network" "vpc" { + name = "<%= ctx[:vars]['network'] %>" +} + +resource "google_compute_subnetwork" "subnet" { + name = "<%= ctx[:vars]['network'] %>-subnet" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = google_compute_network.vpc.id +} + +resource "google_compute_address" "source-addr" { + name = "<%= ctx[:vars]['source_addr'] %>" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.42.42" + region = "us-central1" +} + +resource "google_compute_address" "dest-addr" { + name = "<%= ctx[:vars]['dest_addr'] %>" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.43.43" + region = "us-central1" +} diff --git a/templates/terraform/examples/network_management_connectivity_test_instances.tf.erb b/templates/terraform/examples/network_management_connectivity_test_instances.tf.erb new file mode 100644 index 000000000000..e66690edc2c9 --- /dev/null +++ b/templates/terraform/examples/network_management_connectivity_test_instances.tf.erb @@ -0,0 +1,55 @@ +resource "google_network_management_connectivity_test" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['primary_resource_name'] %>" + source { + instance = google_compute_instance.source.id + } + + destination { + instance = google_compute_instance.destination.id + } + + protocol = "TCP" +} + +resource "google_compute_instance" "source" { + name = "<%= ctx[:vars]['source_instance'] %>" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params { + image = data.google_compute_image.debian_9.self_link + } + } + + network_interface { + network = google_compute_network.vpc.id + access_config { + } + } +} + +resource "google_compute_instance" "destination" { + name = "<%= ctx[:vars]['dest_instance'] %>" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params { + image = data.google_compute_image.debian_9.self_link + } + } + + network_interface { + network = google_compute_network.vpc.id + access_config { + } + } +} + +resource "google_compute_network" "vpc" { + name = "<%= ctx[:vars]['network_name'] %>" +} + +data "google_compute_image" "debian_9" { + family = "debian-9" + project = "debian-cloud" +} diff --git a/third_party/terraform/tests/resource_network_management_connectivity_test_resource_test.go b/third_party/terraform/tests/resource_network_management_connectivity_test_resource_test.go new file mode 100644 index 000000000000..842cc57d4c99 --- /dev/null +++ b/third_party/terraform/tests/resource_network_management_connectivity_test_resource_test.go @@ -0,0 +1,139 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccNetworkManagementConnectivityTest_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkManagementConnectivityTestDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkManagementConnectivityTest_instanceToInstance(context), + }, + { + ResourceName: "google_network_management_connectivity_test.conn-test", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccNetworkManagementConnectivityTest_instanceToAddr(context), + }, + { + ResourceName: "google_network_management_connectivity_test.conn-test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNetworkManagementConnectivityTest_instanceToInstance(context map[string]interface{}) string { + connTestCfg := Nprintf(` +resource "google_network_management_connectivity_test" "conn-test" { + name = "tf-test-conntest%{random_suffix}" + source { + instance = google_compute_instance.vm1.id + } + + destination { + instance = google_compute_instance.vm2.id + } + + protocol = "TCP" +} +`, context) + return fmt.Sprintf("%s\n\n%s\n\n", connTestCfg, testAccNetworkManagementConnectivityTest_baseResources(context)) +} + +func testAccNetworkManagementConnectivityTest_instanceToAddr(context map[string]interface{}) string { + connTestCfg := Nprintf(` +resource "google_network_management_connectivity_test" "conn-test" { + name = "tf-test-conntest%{random_suffix}" + source { + instance = google_compute_instance.vm1.id + network = google_compute_network.vpc.id + port = 50 + } + + destination { + ip_address = google_compute_address.addr.address + project_id = google_compute_address.addr.address + network = google_compute_network.vpc.id + port = 80 + } + + protocol = "TCP" +} +`, context) + return fmt.Sprintf("%s\n\n%s\n\n", connTestCfg, testAccNetworkManagementConnectivityTest_baseResources(context)) +} + +func testAccNetworkManagementConnectivityTest_baseResources(context map[string]interface{}) string { + return Nprintf(` + +resource "google_compute_address" "addr" { + name = "tf-test-addr%{random_suffix}" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.43.43" + region = "us-central1" +} + +resource "google_compute_instance" "vm1" { + name = "tf-test-src-vm%{random_suffix}" + machine_type = "n1-standard-1" + boot_disk { + initialize_params { + image = data.google_compute_image.debian_9.self_link + } + } + network_interface { + network = google_compute_network.vpc.id + } +} + +resource "google_compute_instance" "vm2" { + name = "tf-test-vm-dest%{random_suffix}" + machine_type = "n1-standard-1" + + boot_disk { + initialize_params { + image = data.google_compute_image.debian_9.self_link + } + } + + network_interface { + network = google_compute_network.vpc.id + + } +} + +resource "google_compute_network" "vpc" { + name = "tf-test-connnet%{random_suffix}" +} + +resource "google_compute_subnetwork" "subnet" { + name = "tf-test-connet%{random_suffix}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = google_compute_network.vpc.id +} + +data "google_compute_image" "debian_9" { + family = "debian-9" + project = "debian-cloud" +} +`, context) +}