diff --git a/.changelog/12586.txt b/.changelog/12586.txt new file mode 100644 index 00000000000..70b6a701e97 --- /dev/null +++ b/.changelog/12586.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_edgenetwork_interconnect_attachment` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index f15ab25dd48..d85e9fba275 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -464,9 +464,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 505 +// Generated resources: 506 // Generated IAM resources: 261 -// Total generated resources: 766 +// Total generated resources: 767 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -859,6 +859,7 @@ var generatedResources = map[string]*schema.Resource{ "google_edgecontainer_cluster": edgecontainer.ResourceEdgecontainerCluster(), "google_edgecontainer_node_pool": edgecontainer.ResourceEdgecontainerNodePool(), "google_edgecontainer_vpn_connection": edgecontainer.ResourceEdgecontainerVpnConnection(), + "google_edgenetwork_interconnect_attachment": edgenetwork.ResourceEdgenetworkInterconnectAttachment(), "google_edgenetwork_network": edgenetwork.ResourceEdgenetworkNetwork(), "google_edgenetwork_subnet": edgenetwork.ResourceEdgenetworkSubnet(), "google_essential_contacts_contact": essentialcontacts.ResourceEssentialContactsContact(), diff --git a/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment.go b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment.go new file mode 100644 index 00000000000..e14e9df1a7b --- /dev/null +++ b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment.go @@ -0,0 +1,554 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 edgenetwork + +import ( + "fmt" + "log" + "net/http" + "reflect" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func ResourceEdgenetworkInterconnectAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceEdgenetworkInterconnectAttachmentCreate, + Read: resourceEdgenetworkInterconnectAttachmentRead, + Update: resourceEdgenetworkInterconnectAttachmentUpdate, + Delete: resourceEdgenetworkInterconnectAttachmentDelete, + + Importer: &schema.ResourceImporter{ + State: resourceEdgenetworkInterconnectAttachmentImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.SetLabelsDiff, + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "interconnect": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The ID of the underlying interconnect that this attachment's traffic will traverse through.`, + }, + "interconnect_attachment_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `A unique ID that identifies this interconnect attachment.`, + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The Google Cloud region to which the target Distributed Cloud Edge zone belongs.`, + }, + "network": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + Description: `The ID of the network to which this interconnect attachment belongs. +Must be of the form: 'projects/{{project}}/locations/{{location}}/zones/{{zone}}/networks/{{network_id}}'`, + }, + "vlan_id": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: `VLAN ID provided by user. Must be site-wise unique.`, + }, + "zone": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name of the target Distributed Cloud Edge zone.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `A free-text description of the resource. Max length 1024 characters.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `Labels associated with this resource. + + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "mtu": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: `IP (L3) MTU value of the virtual edge cloud. Default value is '1500'. Possible values are: '1500', '9000'.`, + Default: 1500, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time when the resource was created. +A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine +fractional digits. Examples: '2014-10-02T15:01:23Z' and '2014-10-02T15:01:23.045123456Z'.`, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + ForceNew: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `The canonical name of this resource, with format +'projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}'`, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `The time when the resource was last updated. +A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine +fractional digits. Examples: '2014-10-02T15:01:23Z' and '2014-10-02T15:01:23.045123456Z'.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceEdgenetworkInterconnectAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + descriptionProp, err := expandEdgenetworkInterconnectAttachmentDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + interconnectProp, err := expandEdgenetworkInterconnectAttachmentInterconnect(d.Get("interconnect"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("interconnect"); !tpgresource.IsEmptyValue(reflect.ValueOf(interconnectProp)) && (ok || !reflect.DeepEqual(v, interconnectProp)) { + obj["interconnect"] = interconnectProp + } + networkProp, err := expandEdgenetworkInterconnectAttachmentNetwork(d.Get("network"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network"); !tpgresource.IsEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) { + obj["network"] = networkProp + } + vlanIdProp, err := expandEdgenetworkInterconnectAttachmentVlanId(d.Get("vlan_id"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("vlan_id"); !tpgresource.IsEmptyValue(reflect.ValueOf(vlanIdProp)) && (ok || !reflect.DeepEqual(v, vlanIdProp)) { + obj["vlanId"] = vlanIdProp + } + mtuProp, err := expandEdgenetworkInterconnectAttachmentMtu(d.Get("mtu"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("mtu"); !tpgresource.IsEmptyValue(reflect.ValueOf(mtuProp)) && (ok || !reflect.DeepEqual(v, mtuProp)) { + obj["mtu"] = mtuProp + } + labelsProp, err := expandEdgenetworkInterconnectAttachmentEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{EdgenetworkBasePath}}projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments?interconnectAttachmentId={{interconnect_attachment_id}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new InterconnectAttachment: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for InterconnectAttachment: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error creating InterconnectAttachment: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = EdgenetworkOperationWaitTime( + config, res, project, "Creating InterconnectAttachment", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create InterconnectAttachment: %s", err) + } + + log.Printf("[DEBUG] Finished creating InterconnectAttachment %q: %#v", d.Id(), res) + + return resourceEdgenetworkInterconnectAttachmentRead(d, meta) +} + +func resourceEdgenetworkInterconnectAttachmentRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{EdgenetworkBasePath}}projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for InterconnectAttachment: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("EdgenetworkInterconnectAttachment %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + + if err := d.Set("name", flattenEdgenetworkInterconnectAttachmentName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("labels", flattenEdgenetworkInterconnectAttachmentLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("description", flattenEdgenetworkInterconnectAttachmentDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("create_time", flattenEdgenetworkInterconnectAttachmentCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("update_time", flattenEdgenetworkInterconnectAttachmentUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("interconnect", flattenEdgenetworkInterconnectAttachmentInterconnect(res["interconnect"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("network", flattenEdgenetworkInterconnectAttachmentNetwork(res["network"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("vlan_id", flattenEdgenetworkInterconnectAttachmentVlanId(res["vlanId"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("mtu", flattenEdgenetworkInterconnectAttachmentMtu(res["mtu"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("terraform_labels", flattenEdgenetworkInterconnectAttachmentTerraformLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("effective_labels", flattenEdgenetworkInterconnectAttachmentEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + + return nil +} + +func resourceEdgenetworkInterconnectAttachmentUpdate(d *schema.ResourceData, meta interface{}) error { + // Only the root field "labels" and "terraform_labels" are mutable + return resourceEdgenetworkInterconnectAttachmentRead(d, meta) +} + +func resourceEdgenetworkInterconnectAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for InterconnectAttachment: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{EdgenetworkBasePath}}projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}") + if err != nil { + return err + } + + var obj map[string]interface{} + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + + log.Printf("[DEBUG] Deleting InterconnectAttachment %q", d.Id()) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + Headers: headers, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "InterconnectAttachment") + } + + err = EdgenetworkOperationWaitTime( + config, res, project, "Deleting InterconnectAttachment", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting InterconnectAttachment %q: %#v", d.Id(), res) + return nil +} + +func resourceEdgenetworkInterconnectAttachmentImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/zones/(?P[^/]+)/interconnectAttachment/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenEdgenetworkInterconnectAttachmentName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenEdgenetworkInterconnectAttachmentLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenEdgenetworkInterconnectAttachmentDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenEdgenetworkInterconnectAttachmentCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenEdgenetworkInterconnectAttachmentUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenEdgenetworkInterconnectAttachmentInterconnect(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenEdgenetworkInterconnectAttachmentNetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + return tpgresource.ConvertSelfLinkToV1(v.(string)) +} + +func flattenEdgenetworkInterconnectAttachmentVlanId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); 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 flattenEdgenetworkInterconnectAttachmentMtu(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); 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 flattenEdgenetworkInterconnectAttachmentTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenEdgenetworkInterconnectAttachmentEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandEdgenetworkInterconnectAttachmentDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandEdgenetworkInterconnectAttachmentInterconnect(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandEdgenetworkInterconnectAttachmentNetwork(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + f, err := tpgresource.ParseZonalFieldValue("networks", v.(string), "project", "zone", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for network: %s", err) + } + return f.RelativeLink(), nil +} + +func expandEdgenetworkInterconnectAttachmentVlanId(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandEdgenetworkInterconnectAttachmentMtu(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandEdgenetworkInterconnectAttachmentEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.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/services/edgenetwork/resource_edgenetwork_interconnect_attachment_generated_meta.yaml b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment_generated_meta.yaml new file mode 100644 index 00000000000..4ffc8b0f4d8 --- /dev/null +++ b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment_generated_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_edgenetwork_interconnect_attachment' +generation_type: 'mmv1' +api_service_name: 'edgenetwork.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'InterconnectAttachment' diff --git a/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment_sweeper.go b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment_sweeper.go new file mode 100644 index 00000000000..0b91fd91895 --- /dev/null +++ b/google/services/edgenetwork/resource_edgenetwork_interconnect_attachment_sweeper.go @@ -0,0 +1,161 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 edgenetwork + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("EdgenetworkInterconnectAttachment", testSweepEdgenetworkInterconnectAttachment) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepEdgenetworkInterconnectAttachment(region string) error { + resourceName := "EdgenetworkInterconnectAttachment" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.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 := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://edgenetwork.googleapis.com/v1/projects/{{project}}/locations/{{location}}/aggregated/interconnectAttachments", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["interconnectAttachments"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + var rl []interface{} + zones := resourceList.(map[string]interface{}) + // Loop through every zone in the list response + for _, zonesValue := range zones { + zone := zonesValue.(map[string]interface{}) + for k, v := range zone { + // Zone map either has resources or a warning stating there were no resources found in the zone + if k != "warning" { + resourcesInZone := v.([]interface{}) + rl = append(rl, resourcesInZone...) + } + } + } + + 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{}) + var name string + // Id detected in the delete URL, attempt to use id. + if obj["id"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["id"].(string)) + } else if obj["name"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + } else { + log.Printf("[INFO][SWEEPER_LOG] %s resource name and id were nil", resourceName) + return nil + } + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://edgenetwork.googleapis.com/v1/projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}" + if obj["zone"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource zone was nil", resourceName) + return nil + } + zone := tpgresource.GetResourceNameFromSelfLink(obj["zone"].(string)) + deleteTemplate = strings.Replace(deleteTemplate, "{{zone}}", zone, -1) + + deleteUrl, err := tpgresource.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 = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + 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/website/docs/r/edgenetwork_interconnect_attachment.html.markdown b/website/docs/r/edgenetwork_interconnect_attachment.html.markdown new file mode 100644 index 00000000000..6b444ff2130 --- /dev/null +++ b/website/docs/r/edgenetwork_interconnect_attachment.html.markdown @@ -0,0 +1,182 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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: "Distributed Cloud Edge Network" +description: |- + A Distributed Cloud Edge interconnect attachment, which connects routers to the northbound network. +--- + +# google_edgenetwork_interconnect_attachment + +A Distributed Cloud Edge interconnect attachment, which connects routers to the northbound network. + + +To get more information about InterconnectAttachment, see: + +* [API documentation](https://cloud.google.com/distributed-cloud/edge/latest/docs/reference/network/rest/v1/projects.locations.zones.interconnectAttachments) +* How-to Guides + * [Create and manage interconnect attachments](https://cloud.google.com/distributed-cloud/edge/latest/docs/attachments#api) + +## Example Usage - Edgenetwork Interconnect Attachment + + +```hcl + +resource "google_edgenetwork_interconnect_attachment" "example_interconnect_attachment" { + interconnect_attachment_id = "example-interconnect-attachment" + location = "us-west1" + zone = "" + description = "Example interconnect attachment." + network = google_edgenetwork_network.example_network.id + interconnect = "11111111-2222-3333-4444-555555555555" + vlan_id = 55 + mtu = 9000 + labels = { + "environment" : "dev" + } +} + +resource "google_edgenetwork_network" "example_network" { + network_id = "example-network" + location = "us-west1" + zone = "" + description = "Example network." + mtu = 9000 +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `interconnect` - + (Required) + The ID of the underlying interconnect that this attachment's traffic will traverse through. + +* `network` - + (Required) + The ID of the network to which this interconnect attachment belongs. + Must be of the form: `projects/{{project}}/locations/{{location}}/zones/{{zone}}/networks/{{network_id}}` + +* `vlan_id` - + (Required) + VLAN ID provided by user. Must be site-wise unique. + +* `location` - + (Required) + The Google Cloud region to which the target Distributed Cloud Edge zone belongs. + +* `zone` - + (Required) + The name of the target Distributed Cloud Edge zone. + +* `interconnect_attachment_id` - + (Required) + A unique ID that identifies this interconnect attachment. + + +- - - + + +* `labels` - + (Optional) + Labels associated with this resource. + + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. + Please refer to the field `effective_labels` for all of the labels present on the resource. + +* `description` - + (Optional) + A free-text description of the resource. Max length 1024 characters. + +* `mtu` - + (Optional) + IP (L3) MTU value of the virtual edge cloud. Default value is `1500`. Possible values are: `1500`, `9000`. + +* `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/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}` + +* `name` - + The canonical name of this resource, with format + `projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachments/{{interconnect_attachment_id}}` + +* `create_time` - + The time when the resource was created. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine + fractional digits. Examples: `2014-10-02T15:01:23Z` and `2014-10-02T15:01:23.045123456Z`. + +* `update_time` - + The time when the resource was last updated. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine + fractional digits. Examples: `2014-10-02T15:01:23Z` and `2014-10-02T15:01:23.045123456Z`. + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 30 minutes. + +## Import + + +InterconnectAttachment can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachment/{{interconnect_attachment_id}}` +* `{{project}}/{{location}}/{{zone}}/{{interconnect_attachment_id}}` +* `{{location}}/{{zone}}/{{interconnect_attachment_id}}` +* `{{location}}/{{interconnect_attachment_id}}` +* `{{name}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import InterconnectAttachment using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachment/{{interconnect_attachment_id}}" + to = google_edgenetwork_interconnect_attachment.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), InterconnectAttachment can be imported using one of the formats above. For example: + +``` +$ terraform import google_edgenetwork_interconnect_attachment.default projects/{{project}}/locations/{{location}}/zones/{{zone}}/interconnectAttachment/{{interconnect_attachment_id}} +$ terraform import google_edgenetwork_interconnect_attachment.default {{project}}/{{location}}/{{zone}}/{{interconnect_attachment_id}} +$ terraform import google_edgenetwork_interconnect_attachment.default {{location}}/{{zone}}/{{interconnect_attachment_id}} +$ terraform import google_edgenetwork_interconnect_attachment.default {{location}}/{{interconnect_attachment_id}} +$ terraform import google_edgenetwork_interconnect_attachment.default {{name}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).