diff --git a/.changelog/3601.txt b/.changelog/3601.txt new file mode 100644 index 00000000000..dd62dd7d827 --- /dev/null +++ b/.changelog/3601.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_network_management_connectivity_test` +``` diff --git a/google/config.go b/google/config.go index 182e880ecdf..16e237a463f 100644 --- a/google/config.go +++ b/google/config.go @@ -108,6 +108,7 @@ type Config struct { LoggingBasePath string MLEngineBasePath string MonitoringBasePath string + NetworkManagementBasePath string OSLoginBasePath string PubsubBasePath string RedisBasePath string @@ -249,6 +250,7 @@ var KMSDefaultBasePath = "https://cloudkms.googleapis.com/v1/" var LoggingDefaultBasePath = "https://logging.googleapis.com/v2/" var MLEngineDefaultBasePath = "https://ml.googleapis.com/v1/" var MonitoringDefaultBasePath = "https://monitoring.googleapis.com/" +var NetworkManagementDefaultBasePath = "https://networkmanagement.googleapis.com/v1/" var OSLoginDefaultBasePath = "https://oslogin.googleapis.com/v1/" var PubsubDefaultBasePath = "https://pubsub.googleapis.com/v1/" var RedisDefaultBasePath = "https://redis.googleapis.com/v1/" @@ -765,6 +767,7 @@ func ConfigureBasePaths(c *Config) { c.LoggingBasePath = LoggingDefaultBasePath c.MLEngineBasePath = MLEngineDefaultBasePath c.MonitoringBasePath = MonitoringDefaultBasePath + c.NetworkManagementBasePath = NetworkManagementDefaultBasePath c.OSLoginBasePath = OSLoginDefaultBasePath c.PubsubBasePath = PubsubDefaultBasePath c.RedisBasePath = RedisDefaultBasePath diff --git a/google/network_management_operation.go b/google/network_management_operation.go new file mode 100644 index 00000000000..6250148f112 --- /dev/null +++ b/google/network_management_operation.go @@ -0,0 +1,72 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- +package google + +import ( + "encoding/json" + "fmt" + "time" +) + +type NetworkManagementOperationWaiter struct { + Config *Config + Project string + CommonOperationWaiter +} + +func (w *NetworkManagementOperationWaiter) QueryOp() (interface{}, error) { + if w == nil { + return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") + } + // Returns the proper get. + url := fmt.Sprintf("https://networkmanagement.googleapis.com/v1/%s", w.CommonOperationWaiter.Op.Name) + return sendRequest(w.Config, "GET", w.Project, url, nil) +} + +func createNetworkManagementWaiter(config *Config, op map[string]interface{}, project, activity string) (*NetworkManagementOperationWaiter, error) { + if val, ok := op["name"]; !ok || val == "" { + // This was a synchronous call - there is no operation to wait for. + return nil, nil + } + w := &NetworkManagementOperationWaiter{ + Config: config, + Project: project, + } + if err := w.CommonOperationWaiter.SetOp(op); err != nil { + return nil, err + } + return w, nil +} + +// nolint: deadcode,unused +func networkManagementOperationWaitTimeWithResponse(config *Config, op map[string]interface{}, response *map[string]interface{}, project, activity string, timeout time.Duration) error { + w, err := createNetworkManagementWaiter(config, op, project, activity) + if err != nil || w == nil { + // If w is nil, the op was synchronous. + return err + } + if err := OperationWait(w, activity, timeout, config.PollInterval); err != nil { + return err + } + return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response) +} + +func networkManagementOperationWaitTime(config *Config, op map[string]interface{}, project, activity string, timeout time.Duration) error { + w, err := createNetworkManagementWaiter(config, op, project, activity) + if err != nil || w == nil { + // If w is nil, the op was synchronous. + return err + } + return OperationWait(w, activity, timeout, config.PollInterval) +} diff --git a/google/provider.go b/google/provider.go index 2f1884760e8..43ba26bed36 100644 --- a/google/provider.go +++ b/google/provider.go @@ -341,6 +341,14 @@ func Provider() terraform.ResourceProvider { "GOOGLE_MONITORING_CUSTOM_ENDPOINT", }, MonitoringDefaultBasePath), }, + "network_management_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateCustomEndpoint, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_NETWORK_MANAGEMENT_CUSTOM_ENDPOINT", + }, NetworkManagementDefaultBasePath), + }, "os_login_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -563,9 +571,9 @@ func Provider() terraform.ResourceProvider { return provider } -// Generated resources: 134 +// Generated resources: 135 // Generated IAM resources: 57 -// Total generated resources: 191 +// Total generated resources: 192 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -728,6 +736,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_monitoring_custom_service": resourceMonitoringService(), "google_monitoring_slo": resourceMonitoringSlo(), "google_monitoring_uptime_check_config": resourceMonitoringUptimeCheckConfig(), + "google_network_management_connectivity_test": resourceNetworkManagementConnectivityTest(), "google_os_login_ssh_public_key": resourceOSLoginSSHPublicKey(), "google_pubsub_topic": resourcePubsubTopic(), "google_pubsub_topic_iam_binding": ResourceIamBinding(PubsubTopicIamSchema, PubsubTopicIamUpdaterProducer, PubsubTopicIdParseFunc), @@ -959,6 +968,7 @@ func providerConfigure(d *schema.ResourceData, p *schema.Provider, terraformVers config.LoggingBasePath = d.Get("logging_custom_endpoint").(string) config.MLEngineBasePath = d.Get("ml_engine_custom_endpoint").(string) config.MonitoringBasePath = d.Get("monitoring_custom_endpoint").(string) + config.NetworkManagementBasePath = d.Get("network_management_custom_endpoint").(string) config.OSLoginBasePath = d.Get("os_login_custom_endpoint").(string) config.PubsubBasePath = d.Get("pubsub_custom_endpoint").(string) config.RedisBasePath = d.Get("redis_custom_endpoint").(string) diff --git a/google/resource_network_management_connectivity_test_resource.go b/google/resource_network_management_connectivity_test_resource.go new file mode 100644 index 00000000000..34e66ecbfc0 --- /dev/null +++ b/google/resource_network_management_connectivity_test_resource.go @@ -0,0 +1,845 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "log" + "reflect" + "strconv" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceNetworkManagementConnectivityTest() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkManagementConnectivityTestCreate, + Read: resourceNetworkManagementConnectivityTestRead, + Update: resourceNetworkManagementConnectivityTestUpdate, + Delete: resourceNetworkManagementConnectivityTestDelete, + + Importer: &schema.ResourceImporter{ + State: resourceNetworkManagementConnectivityTestImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Minute), + Delete: schema.DefaultTimeout(4 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "destination": { + Type: schema.TypeList, + 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.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Optional: true, + Description: `A Compute Engine instance URI.`, + }, + "ip_address": { + Type: schema.TypeString, + Optional: true, + 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.`, + }, + "network": { + Type: schema.TypeString, + Optional: true, + Description: `A Compute Engine network URI.`, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + Description: `The IP protocol port of the endpoint. Only applicable when +protocol is TCP or UDP.`, + }, + "project_id": { + Type: schema.TypeString, + Optional: true, + 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.`, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Unique name for the connectivity test.`, + }, + "source": { + Type: schema.TypeList, + 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.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Optional: true, + Description: `A Compute Engine instance URI.`, + }, + "ip_address": { + Type: schema.TypeString, + Optional: true, + 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.`, + }, + "network": { + Type: schema.TypeString, + Optional: true, + Description: `A Compute Engine network URI.`, + }, + "network_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"GCP_NETWORK", "NON_GCP_NETWORK", ""}, false), + Description: `Type of the network where the endpoint is located. Possible values: ["GCP_NETWORK", "NON_GCP_NETWORK"]`, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + Description: `The IP protocol port of the endpoint. Only applicable when +protocol is TCP or UDP.`, + }, + "project_id": { + Type: schema.TypeString, + Optional: true, + 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.`, + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `The user-supplied description of the Connectivity Test. +Maximum of 512 characters.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `Resource labels to represent user-provided metadata.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "protocol": { + Type: schema.TypeString, + Optional: true, + Description: `IP Protocol of the test. When not provided, "TCP" is assumed.`, + Default: "TCP", + }, + "related_projects": { + Type: schema.TypeList, + Optional: true, + Description: `Other projects that may be relevant for reachability analysis. +This is applicable to scenarios where a test can cross project +boundaries.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } +} + +func resourceNetworkManagementConnectivityTestCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + obj := make(map[string]interface{}) + nameProp, err := expandNetworkManagementConnectivityTestName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandNetworkManagementConnectivityTestDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + sourceProp, err := expandNetworkManagementConnectivityTestSource(d.Get("source"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source"); !isEmptyValue(reflect.ValueOf(sourceProp)) && (ok || !reflect.DeepEqual(v, sourceProp)) { + obj["source"] = sourceProp + } + destinationProp, err := expandNetworkManagementConnectivityTestDestination(d.Get("destination"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("destination"); !isEmptyValue(reflect.ValueOf(destinationProp)) && (ok || !reflect.DeepEqual(v, destinationProp)) { + obj["destination"] = destinationProp + } + protocolProp, err := expandNetworkManagementConnectivityTestProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(protocolProp)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + relatedProjectsProp, err := expandNetworkManagementConnectivityTestRelatedProjects(d.Get("related_projects"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("related_projects"); !isEmptyValue(reflect.ValueOf(relatedProjectsProp)) && (ok || !reflect.DeepEqual(v, relatedProjectsProp)) { + obj["relatedProjects"] = relatedProjectsProp + } + labelsProp, err := expandNetworkManagementConnectivityTestLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := replaceVars(d, config, "{{NetworkManagementBasePath}}projects/{{project}}/locations/global/connectivityTests?testId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new ConnectivityTest: %#v", obj) + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "POST", project, url, obj, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return fmt.Errorf("Error creating ConnectivityTest: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + // Use the resource in the operation response to populate + // identity fields and d.Id() before read + var opRes map[string]interface{} + err = networkManagementOperationWaitTimeWithResponse( + config, res, &opRes, project, "Creating ConnectivityTest", + d.Timeout(schema.TimeoutCreate)) + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create ConnectivityTest: %s", err) + } + + if err := d.Set("name", flattenNetworkManagementConnectivityTestName(opRes["name"], d, config)); err != nil { + return err + } + + // This may have caused the ID to update - update it if so. + id, err = replaceVars(d, config, "projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating ConnectivityTest %q: %#v", d.Id(), res) + + return resourceNetworkManagementConnectivityTestRead(d, meta) +} + +func resourceNetworkManagementConnectivityTestRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + url, err := replaceVars(d, config, "{{NetworkManagementBasePath}}projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + res, err := sendRequest(config, "GET", project, url, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("NetworkManagementConnectivityTest %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + + if err := d.Set("name", flattenNetworkManagementConnectivityTestName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("description", flattenNetworkManagementConnectivityTestDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("source", flattenNetworkManagementConnectivityTestSource(res["source"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("destination", flattenNetworkManagementConnectivityTestDestination(res["destination"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("protocol", flattenNetworkManagementConnectivityTestProtocol(res["protocol"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("related_projects", flattenNetworkManagementConnectivityTestRelatedProjects(res["relatedProjects"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + if err := d.Set("labels", flattenNetworkManagementConnectivityTestLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading ConnectivityTest: %s", err) + } + + return nil +} + +func resourceNetworkManagementConnectivityTestUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + descriptionProp, err := expandNetworkManagementConnectivityTestDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + sourceProp, err := expandNetworkManagementConnectivityTestSource(d.Get("source"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sourceProp)) { + obj["source"] = sourceProp + } + destinationProp, err := expandNetworkManagementConnectivityTestDestination(d.Get("destination"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("destination"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, destinationProp)) { + obj["destination"] = destinationProp + } + protocolProp, err := expandNetworkManagementConnectivityTestProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + relatedProjectsProp, err := expandNetworkManagementConnectivityTestRelatedProjects(d.Get("related_projects"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("related_projects"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, relatedProjectsProp)) { + obj["relatedProjects"] = relatedProjectsProp + } + labelsProp, err := expandNetworkManagementConnectivityTestLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := replaceVars(d, config, "{{NetworkManagementBasePath}}projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating ConnectivityTest %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("source") { + updateMask = append(updateMask, "source.ipAddress", + "source.port", + "source.instance", + "source.network", + "source.networkType", + "source.projectId") + } + + if d.HasChange("destination") { + updateMask = append(updateMask, "destination.ipAddress", + "destination.port", + "destination.instance", + "destination.network", + "destination.projectId") + } + + if d.HasChange("protocol") { + updateMask = append(updateMask, "protocol") + } + + if d.HasChange("related_projects") { + updateMask = append(updateMask, "relatedProjects") + } + + if d.HasChange("labels") { + updateMask = append(updateMask, "labels") + } + // updateMask is a URL parameter but not present in the schema, so replaceVars + // won't set it + url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return fmt.Errorf("Error updating ConnectivityTest %q: %s", d.Id(), err) + } + + err = networkManagementOperationWaitTime( + config, res, project, "Updating ConnectivityTest", + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourceNetworkManagementConnectivityTestRead(d, meta) +} + +func resourceNetworkManagementConnectivityTestDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "{{NetworkManagementBasePath}}projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting ConnectivityTest %q", d.Id()) + + res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)) + if err != nil { + return handleNotFoundError(err, d, "ConnectivityTest") + } + + err = networkManagementOperationWaitTime( + config, res, project, "Deleting ConnectivityTest", + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting ConnectivityTest %q: %#v", d.Id(), res) + return nil +} + +func resourceNetworkManagementConnectivityTestImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/global/connectivityTests/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVars(d, config, "projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenNetworkManagementConnectivityTestName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + return NameFromSelfLinkStateFunc(v) +} + +func flattenNetworkManagementConnectivityTestDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestSource(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["ip_address"] = + flattenNetworkManagementConnectivityTestSourceIpAddress(original["ipAddress"], d, config) + transformed["port"] = + flattenNetworkManagementConnectivityTestSourcePort(original["port"], d, config) + transformed["instance"] = + flattenNetworkManagementConnectivityTestSourceInstance(original["instance"], d, config) + transformed["network"] = + flattenNetworkManagementConnectivityTestSourceNetwork(original["network"], d, config) + transformed["network_type"] = + flattenNetworkManagementConnectivityTestSourceNetworkType(original["networkType"], d, config) + transformed["project_id"] = + flattenNetworkManagementConnectivityTestSourceProjectId(original["projectId"], d, config) + return []interface{}{transformed} +} +func flattenNetworkManagementConnectivityTestSourceIpAddress(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestSourcePort(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenNetworkManagementConnectivityTestSourceInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestSourceNetwork(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestSourceNetworkType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestSourceProjectId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestDestination(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["ip_address"] = + flattenNetworkManagementConnectivityTestDestinationIpAddress(original["ipAddress"], d, config) + transformed["port"] = + flattenNetworkManagementConnectivityTestDestinationPort(original["port"], d, config) + transformed["instance"] = + flattenNetworkManagementConnectivityTestDestinationInstance(original["instance"], d, config) + transformed["network"] = + flattenNetworkManagementConnectivityTestDestinationNetwork(original["network"], d, config) + transformed["project_id"] = + flattenNetworkManagementConnectivityTestDestinationProjectId(original["projectId"], d, config) + return []interface{}{transformed} +} +func flattenNetworkManagementConnectivityTestDestinationIpAddress(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestDestinationPort(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenNetworkManagementConnectivityTestDestinationInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestDestinationNetwork(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestDestinationProjectId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestProtocol(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestRelatedProjects(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenNetworkManagementConnectivityTestLabels(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func expandNetworkManagementConnectivityTestName(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 +} + +func expandNetworkManagementConnectivityTestDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSource(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedIpAddress, err := expandNetworkManagementConnectivityTestSourceIpAddress(original["ip_address"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIpAddress); val.IsValid() && !isEmptyValue(val) { + transformed["ipAddress"] = transformedIpAddress + } + + transformedPort, err := expandNetworkManagementConnectivityTestSourcePort(original["port"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPort); val.IsValid() && !isEmptyValue(val) { + transformed["port"] = transformedPort + } + + transformedInstance, err := expandNetworkManagementConnectivityTestSourceInstance(original["instance"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInstance); val.IsValid() && !isEmptyValue(val) { + transformed["instance"] = transformedInstance + } + + transformedNetwork, err := expandNetworkManagementConnectivityTestSourceNetwork(original["network"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNetwork); val.IsValid() && !isEmptyValue(val) { + transformed["network"] = transformedNetwork + } + + transformedNetworkType, err := expandNetworkManagementConnectivityTestSourceNetworkType(original["network_type"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNetworkType); val.IsValid() && !isEmptyValue(val) { + transformed["networkType"] = transformedNetworkType + } + + transformedProjectId, err := expandNetworkManagementConnectivityTestSourceProjectId(original["project_id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) { + transformed["projectId"] = transformedProjectId + } + + return transformed, nil +} + +func expandNetworkManagementConnectivityTestSourceIpAddress(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSourcePort(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSourceInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSourceNetwork(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSourceNetworkType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestSourceProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestDestination(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedIpAddress, err := expandNetworkManagementConnectivityTestDestinationIpAddress(original["ip_address"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIpAddress); val.IsValid() && !isEmptyValue(val) { + transformed["ipAddress"] = transformedIpAddress + } + + transformedPort, err := expandNetworkManagementConnectivityTestDestinationPort(original["port"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPort); val.IsValid() && !isEmptyValue(val) { + transformed["port"] = transformedPort + } + + transformedInstance, err := expandNetworkManagementConnectivityTestDestinationInstance(original["instance"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedInstance); val.IsValid() && !isEmptyValue(val) { + transformed["instance"] = transformedInstance + } + + transformedNetwork, err := expandNetworkManagementConnectivityTestDestinationNetwork(original["network"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNetwork); val.IsValid() && !isEmptyValue(val) { + transformed["network"] = transformedNetwork + } + + transformedProjectId, err := expandNetworkManagementConnectivityTestDestinationProjectId(original["project_id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) { + transformed["projectId"] = transformedProjectId + } + + return transformed, nil +} + +func expandNetworkManagementConnectivityTestDestinationIpAddress(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestDestinationPort(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestDestinationInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestDestinationNetwork(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestDestinationProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestProtocol(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestRelatedProjects(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandNetworkManagementConnectivityTestLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google/resource_network_management_connectivity_test_resource_generated_test.go b/google/resource_network_management_connectivity_test_resource_generated_test.go new file mode 100644 index 00000000000..ea7e01fb48e --- /dev/null +++ b/google/resource_network_management_connectivity_test_resource_generated_test.go @@ -0,0 +1,208 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccNetworkManagementConnectivityTest_networkManagementConnectivityTestInstancesExample(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_networkManagementConnectivityTestInstancesExample(context), + }, + { + ResourceName: "google_network_management_connectivity_test.instance-test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNetworkManagementConnectivityTest_networkManagementConnectivityTestInstancesExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_network_management_connectivity_test" "instance-test" { + name = "tf-test-conn-test-instances%{random_suffix}" + source { + instance = google_compute_instance.source.id + } + + destination { + instance = google_compute_instance.destination.id + } + + protocol = "TCP" +} + +resource "google_compute_instance" "source" { + name = "tf-test-source-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 + access_config { + } + } +} + +resource "google_compute_instance" "destination" { + name = "tf-test-dest-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 + access_config { + } + } +} + +resource "google_compute_network" "vpc" { + name = "tf-test-conn-test-net%{random_suffix}" +} + +data "google_compute_image" "debian_9" { + family = "debian-9" + project = "debian-cloud" +} +`, context) +} + +func TestAccNetworkManagementConnectivityTest_networkManagementConnectivityTestAddressesExample(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_networkManagementConnectivityTestAddressesExample(context), + }, + { + ResourceName: "google_network_management_connectivity_test.address-test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNetworkManagementConnectivityTest_networkManagementConnectivityTestAddressesExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_network_management_connectivity_test" "address-test" { + name = "tf-test-conn-test-addr%{random_suffix}" + 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 = "tf-test-connectivity-vpc%{random_suffix}" +} + +resource "google_compute_subnetwork" "subnet" { + name = "tf-test-connectivity-vpc%{random_suffix}-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 = "tf-test-src-addr%{random_suffix}" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.42.42" + region = "us-central1" +} + +resource "google_compute_address" "dest-addr" { + name = "tf-test-dest-addr%{random_suffix}" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.43.43" + region = "us-central1" +} +`, context) +} + +func testAccCheckNetworkManagementConnectivityTestDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_network_management_connectivity_test" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + url, err := replaceVarsForTest(config, rs, "{{NetworkManagementBasePath}}projects/{{project}}/locations/global/connectivityTests/{{name}}") + if err != nil { + return err + } + + _, err = sendRequest(config, "GET", "", url, nil) + if err == nil { + return fmt.Errorf("NetworkManagementConnectivityTest still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/resource_network_management_connectivity_test_resource_sweeper_test.go b/google/resource_network_management_connectivity_test_resource_sweeper_test.go new file mode 100644 index 00000000000..07a77242d07 --- /dev/null +++ b/google/resource_network_management_connectivity_test_resource_sweeper_test.go @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func init() { + resource.AddTestSweepers("NetworkManagementConnectivityTest", &resource.Sweeper{ + Name: "NetworkManagementConnectivityTest", + F: testSweepNetworkManagementConnectivityTest, + }) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepNetworkManagementConnectivityTest(region string) error { + resourceName := "NetworkManagementConnectivityTest" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://networkmanagement.googleapis.com/v1/projects/{{project}}/locations/global/connectivityTests", "?")[0] + listUrl, err := replaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := sendRequest(config, "GET", config.Project, listUrl, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["connectivityTests"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !isSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://networkmanagement.googleapis.com/v1/projects/{{project}}/locations/global/connectivityTests/{{name}}" + deleteUrl, err := replaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = sendRequest(config, "DELETE", config.Project, deleteUrl, nil) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/resource_network_management_connectivity_test_resource_test.go b/google/resource_network_management_connectivity_test_resource_test.go new file mode 100644 index 00000000000..842cc57d4c9 --- /dev/null +++ b/google/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) +} diff --git a/website/docs/r/network_management_connectivity_test_resource.html.markdown b/website/docs/r/network_management_connectivity_test_resource.html.markdown new file mode 100644 index 00000000000..64243d56622 --- /dev/null +++ b/website/docs/r/network_management_connectivity_test_resource.html.markdown @@ -0,0 +1,336 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "NetworkManagement" +layout: "google" +page_title: "Google: google_network_management_connectivity_test" +sidebar_current: "docs-google-network-management-connectivity-test" +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. +--- + +# google\_network\_management\_connectivity\_test + +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. + + +To get more information about ConnectivityTest, see: + +* [API documentation](https://cloud.google.com/network-intelligence-center/docs/connectivity-tests/reference/networkmanagement/rest/v1/projects.locations.global.connectivityTests) +* How-to Guides + * [Official Documentation](https://cloud.google.com/network-intelligence-center/docs) + + +## Example Usage - Network Management Connectivity Test Instances + + +```hcl +resource "google_network_management_connectivity_test" "instance-test" { + name = "conn-test-instances" + source { + instance = google_compute_instance.source.id + } + + destination { + instance = google_compute_instance.destination.id + } + + protocol = "TCP" +} + +resource "google_compute_instance" "source" { + name = "source-vm" + 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 = "dest-vm" + 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 = "conn-test-net" +} + +data "google_compute_image" "debian_9" { + family = "debian-9" + project = "debian-cloud" +} +``` + +## Example Usage - Network Management Connectivity Test Addresses + + +```hcl +resource "google_network_management_connectivity_test" "address-test" { + name = "conn-test-addr" + 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 = "connectivity-vpc" +} + +resource "google_compute_subnetwork" "subnet" { + name = "connectivity-vpc-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 = "src-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 = "dest-addr" + subnetwork = google_compute_subnetwork.subnet.id + address_type = "INTERNAL" + address = "10.0.43.43" + region = "us-central1" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + Unique name for the connectivity test. + +* `source` - + (Required) + 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. Structure is documented below. + +* `destination` - + (Required) + 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. Structure is documented below. + + +The `source` block supports: + +* `ip_address` - + (Optional) + 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. + +* `port` - + (Optional) + The IP protocol port of the endpoint. Only applicable when + protocol is TCP or UDP. + +* `instance` - + (Optional) + A Compute Engine instance URI. + +* `network` - + (Optional) + A Compute Engine network URI. + +* `network_type` - + (Optional) + Type of the network where the endpoint is located. + + Possible values are: + * `GCP_NETWORK` + * `NON_GCP_NETWORK` + +* `project_id` - + (Optional) + 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. + +The `destination` block supports: + +* `ip_address` - + (Optional) + 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. + +* `port` - + (Optional) + The IP protocol port of the endpoint. Only applicable when + protocol is TCP or UDP. + +* `instance` - + (Optional) + A Compute Engine instance URI. + +* `network` - + (Optional) + A Compute Engine network URI. + +* `project_id` - + (Optional) + 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. + +- - - + + +* `description` - + (Optional) + The user-supplied description of the Connectivity Test. + Maximum of 512 characters. + +* `protocol` - + (Optional) + IP Protocol of the test. When not provided, "TCP" is assumed. + +* `related_projects` - + (Optional) + Other projects that may be relevant for reachability analysis. + This is applicable to scenarios where a test can cross project + boundaries. + +* `labels` - + (Optional) + Resource labels to represent user-provided metadata. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/global/connectivityTests/{{name}}` + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +ConnectivityTest can be imported using any of these accepted formats: + +``` +$ terraform import google_network_management_connectivity_test.default projects/{{project}}/locations/global/connectivityTests/{{name}} +$ terraform import google_network_management_connectivity_test.default {{project}}/{{name}} +$ terraform import google_network_management_connectivity_test.default {{name}} +``` + +-> If you're importing a resource with beta features, make sure to include `-provider=google-beta` +as an argument so that Terraform uses the correct provider to import your resource. + +## User Project Overrides + +This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override). diff --git a/website/google.erb b/website/google.erb index e1b1b1a45d1..bfe49976501 100644 --- a/website/google.erb +++ b/website/google.erb @@ -1810,6 +1810,22 @@ +
  • + NetworkManagement + +
  • +
  • OS Login