From 2344cedb117a678c562c0517dcafed3a9d07417b Mon Sep 17 00:00:00 2001 From: Nathan McKinley Date: Tue, 29 May 2018 23:15:03 +0000 Subject: [PATCH] WIP: Add interconnect attachments. Fixes #1140. --- google/provider_compute_gen.go | 21 +- ...esource_compute_interconnect_attachment.go | 386 ++++++++++++++++++ ...pute_interconnect_attachment.html.markdown | 118 ++++++ 3 files changed, 515 insertions(+), 10 deletions(-) create mode 100644 google/resource_compute_interconnect_attachment.go create mode 100644 website/docs/r/compute_interconnect_attachment.html.markdown diff --git a/google/provider_compute_gen.go b/google/provider_compute_gen.go index 53652ff72fc..34164b1d910 100644 --- a/google/provider_compute_gen.go +++ b/google/provider_compute_gen.go @@ -17,14 +17,15 @@ package google import "github.com/hashicorp/terraform/helper/schema" var GeneratedComputeResourcesMap = map[string]*schema.Resource{ - "google_compute_backend_bucket": resourceComputeBackendBucket(), - "google_compute_global_address": resourceComputeGlobalAddress(), - "google_compute_http_health_check": resourceComputeHttpHealthCheck(), - "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), - "google_compute_ssl_policy": resourceComputeSslPolicy(), - "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), - "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), - "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), - "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), - "google_compute_vpn_gateway": resourceComputeVpnGateway(), + "google_compute_backend_bucket": resourceComputeBackendBucket(), + "google_compute_global_address": resourceComputeGlobalAddress(), + "google_compute_http_health_check": resourceComputeHttpHealthCheck(), + "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), + "google_compute_interconnect_attachment": resourceComputeInterconnectAttachment(), + "google_compute_ssl_policy": resourceComputeSslPolicy(), + "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), + "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), + "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), + "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), + "google_compute_vpn_gateway": resourceComputeVpnGateway(), } diff --git a/google/resource_compute_interconnect_attachment.go b/google/resource_compute_interconnect_attachment.go new file mode 100644 index 00000000000..7857bf9aaef --- /dev/null +++ b/google/resource_compute_interconnect_attachment.go @@ -0,0 +1,386 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "strconv" + "time" + + "github.com/hashicorp/terraform/helper/schema" + compute "google.golang.org/api/compute/v1" +) + +func resourceComputeInterconnectAttachment() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeInterconnectAttachmentCreate, + Read: resourceComputeInterconnectAttachmentRead, + Delete: resourceComputeInterconnectAttachmentDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeInterconnectAttachmentImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + + Schema: map[string]*schema.Schema{ + "interconnect": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "router": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "region": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "cloud_router_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "customer_router_ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "google_reference_id": { + Type: schema.TypeString, + Computed: true, + }, + "operational_status": { + Type: schema.TypeString, + Computed: true, + }, + "private_interconnect_info": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "tag8021q": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceComputeInterconnectAttachmentCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + interconnectProp, err := expandComputeInterconnectAttachmentInterconnect(d.Get("interconnect"), d, config) + if err != nil { + return err + } + descriptionProp, err := expandComputeInterconnectAttachmentDescription(d.Get("description"), d, config) + if err != nil { + return err + } + routerProp, err := expandComputeInterconnectAttachmentRouter(d.Get("router"), d, config) + if err != nil { + return err + } + regionProp, err := expandComputeInterconnectAttachmentRegion(d.Get("region"), d, config) + if err != nil { + return err + } + nameProp, err := expandComputeInterconnectAttachmentName(d.Get("name"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "interconnect": interconnectProp, + "description": descriptionProp, + "router": routerProp, + "region": regionProp, + "name": nameProp, + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/interconnectAttachments") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new InterconnectAttachment: %#v", obj) + res, err := Post(config, url, obj) + if err != nil { + return fmt.Errorf("Error creating InterconnectAttachment: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating InterconnectAttachment", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create InterconnectAttachment: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating InterconnectAttachment %q: %#v", d.Id(), res) + + return resourceComputeInterconnectAttachmentRead(d, meta) +} + +func resourceComputeInterconnectAttachmentRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/interconnectAttachments/{{name}}") + if err != nil { + return err + } + + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeInterconnectAttachment %q", d.Id())) + } + + if err := d.Set("cloud_router_ip_address", flattenComputeInterconnectAttachmentCloudRouterIpAddress(res["cloudRouterIpAddress"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("customer_router_ip_address", flattenComputeInterconnectAttachmentCustomerRouterIpAddress(res["customerRouterIpAddress"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("interconnect", flattenComputeInterconnectAttachmentInterconnect(res["interconnect"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("description", flattenComputeInterconnectAttachmentDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("private_interconnect_info", flattenComputeInterconnectAttachmentPrivateInterconnectInfo(res["privateInterconnectInfo"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("google_reference_id", flattenComputeInterconnectAttachmentGoogleReferenceId(res["googleReferenceId"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("operational_status", flattenComputeInterconnectAttachmentOperationalStatus(res["operationalStatus"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("router", flattenComputeInterconnectAttachmentRouter(res["router"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("region", flattenComputeInterconnectAttachmentRegion(res["region"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeInterconnectAttachmentCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("name", flattenComputeInterconnectAttachmentName(res["name"])); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading InterconnectAttachment: %s", err) + } + + return nil +} + +func resourceComputeInterconnectAttachmentDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/interconnectAttachments/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting InterconnectAttachment %q", d.Id()) + res, err := Delete(config, url) + if err != nil { + return fmt.Errorf("Error deleting InterconnectAttachment %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting InterconnectAttachment", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting InterconnectAttachment %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeInterconnectAttachmentImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/regions/(?P[^/]+)/interconnectAttachments/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeInterconnectAttachmentCloudRouterIpAddress(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentCustomerRouterIpAddress(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentInterconnect(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentDescription(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentPrivateInterconnectInfo(v interface{}) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["tag8021q"] = + flattenComputeInterconnectAttachmentPrivateInterconnectInfoTag8021q(original["tag8021q"]) + return []interface{}{transformed} +} +func flattenComputeInterconnectAttachmentPrivateInterconnectInfoTag8021q(v interface{}) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeInterconnectAttachmentGoogleReferenceId(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentOperationalStatus(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentRouter(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentRegion(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeInterconnectAttachmentName(v interface{}) interface{} { + return v +} + +func expandComputeInterconnectAttachmentInterconnect(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeInterconnectAttachmentDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeInterconnectAttachmentRouter(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeInterconnectAttachmentRegion(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeInterconnectAttachmentName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/website/docs/r/compute_interconnect_attachment.html.markdown b/website/docs/r/compute_interconnect_attachment.html.markdown new file mode 100644 index 00000000000..4966ac0c946 --- /dev/null +++ b/website/docs/r/compute_interconnect_attachment.html.markdown @@ -0,0 +1,118 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** 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. +# +# ---------------------------------------------------------------------------- +layout: "google" +page_title: "Google: google_compute_interconnect_attachment" +sidebar_current: "docs-google-compute-interconnect-attachment" +description: |- + Represents an InterconnectAttachment (VLAN attachment) resource. +--- + +# google\_compute\_interconnect\_attachment + +Represents an InterconnectAttachment (VLAN attachment) resource. For more +information, see Creating VLAN Attachments. + + +## Example Usage + +```hcl +resource "google_compute_interconnect_attachment" "default" { + name = "test-interconnect" + interconnect = "https://googleapis.com/compute/v1/projects/.../global/interconnects/..." + router = "https://googleapis.com/compute/v1/projects/.../regions/.../routers/..." +} +``` + +## Argument Reference + +The following arguments are supported: + +* `interconnect` - + (Required) + URL of the underlying Interconnect object that this attachment's traffic will + traverse through. +* `router` - + (Required) + URL of the cloud router to be used for dynamic routing. This router must be in + the same region as this InterconnectAttachment. The InterconnectAttachment will + automatically connect the Interconnect to the network & region within which the + Cloud Router is configured. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is created. The + name must be 1-63 characters long, and comply with RFC1035. Specifically, the + name must be 1-63 characters long and match the regular expression + `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a + lowercase letter, and all following characters must be a dash, lowercase + letter, or digit, except the last character, which cannot be a dash. + + +- - - + +* `description` - + (Optional) + An optional description of this resource. +* `region` - + (Optional) + Region where the regional interconnect attachment resides. +* `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: + +* `cloud_router_ip_address` - + [Output Only] IPv4 address + prefix length to be configured on Cloud Router + Interface for this interconnect attachment. +* `customer_router_ip_address` - + [Output Only] IPv4 address + prefix length to be configured on the customer + router subinterface for this interconnect attachment. +* `private_interconnect_info` - + [Output Only] Information specific to an InterconnectAttachment. This property + is populated if the interconnect that this is attached to is of type DEDICATED. Structure is documented below. +* `google_reference_id` - + [Output Only] Google reference ID, to be used when raising support tickets with + Google or otherwise to debug backend connectivity issues. +* `operational_status` - + [Output Only] The current status of whether or not this interconnect attachment + is functional. +* `creation_timestamp` - + [Output Only] Creation timestamp in RFC3339 text format. +* `self_link` - The URI of the created resource. + +The `private_interconnect_info` block contains: +* `tag8021q` - + [Output Only] 802.1q encapsulation tag to be used for traffic between + Google and the customer, going to and from this network and region. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +InterconnectAttachment can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_interconnect_attachment.default projects/{{project}}/regions/{{region}}/interconnectAttachments/{{name}} +$ terraform import google_compute_interconnect_attachment.default {{project}}/{{region}}/{{name}} +$ terraform import google_compute_interconnect_attachment.default {{name}} +```