diff --git a/google/provider_compute_gen.go b/google/provider_compute_gen.go index b5407b92192..f9a86cd8c64 100644 --- a/google/provider_compute_gen.go +++ b/google/provider_compute_gen.go @@ -31,6 +31,7 @@ var GeneratedComputeResourcesMap = map[string]*schema.Resource{ "google_compute_region_disk": resourceComputeRegionDisk(), "google_compute_route": resourceComputeRoute(), "google_compute_router": resourceComputeRouter(), + "google_compute_ssl_certificate": resourceComputeSslCertificate(), "google_compute_ssl_policy": resourceComputeSslPolicy(), "google_compute_subnetwork": resourceComputeSubnetwork(), "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), diff --git a/google/resource_compute_ssl_certificate.go b/google/resource_compute_ssl_certificate.go index 985d7210805..575515b1800 100644 --- a/google/resource_compute_ssl_certificate.go +++ b/google/resource_compute_ssl_certificate.go @@ -1,12 +1,29 @@ +// ---------------------------------------------------------------------------- +// +// *** 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" + "time" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeSslCertificate() *schema.Resource { @@ -16,27 +33,49 @@ func resourceComputeSslCertificate() *schema.Resource { Delete: resourceComputeSslCertificateDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeSslCertificateImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), }, Schema: map[string]*schema.Schema{ - "certificate": &schema.Schema{ + "certificate": { Type: schema.TypeString, Required: true, ForceNew: true, Sensitive: true, }, - - "name": &schema.Schema{ + "private_key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Sensitive: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "name": { Type: schema.TypeString, - Optional: true, Computed: true, + Optional: true, ForceNew: true, - ConflictsWith: []string{"name_prefix"}, ValidateFunc: validateGCPName, + ConflictsWith: []string{"name_prefix"}, }, - - "name_prefix": &schema.Schema{ + "certificate_id": { + Type: schema.TypeInt, + Computed: true, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "name_prefix": { Type: schema.TypeString, Optional: true, Computed: true, @@ -53,33 +92,13 @@ func resourceComputeSslCertificate() *schema.Resource { return }, }, - - "private_key": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - Sensitive: true, - }, - - "description": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - - "certificate_id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "project": &schema.Schema{ + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "self_link": &schema.Schema{ + "self_link": { Type: schema.TypeString, Computed: true, }, @@ -90,44 +109,71 @@ func resourceComputeSslCertificate() *schema.Resource { func resourceComputeSslCertificateCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - project, err := getProject(d, config) + obj := make(map[string]interface{}) + certificateProp, err := expandComputeSslCertificateCertificate(d.Get("certificate"), d, config) if err != nil { return err + } else if v, ok := d.GetOkExists("certificate"); !isEmptyValue(reflect.ValueOf(certificateProp)) && (ok || !reflect.DeepEqual(v, certificateProp)) { + obj["certificate"] = certificateProp } - - var certName string - if v, ok := d.GetOk("name"); ok { - certName = v.(string) - } else if v, ok := d.GetOk("name_prefix"); ok { - certName = resource.PrefixedUniqueId(v.(string)) - } else { - certName = resource.UniqueId() + descriptionProp, err := expandComputeSslCertificateDescription(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 } - - // Build the certificate parameter - cert := &compute.SslCertificate{ - Name: certName, - Certificate: d.Get("certificate").(string), - PrivateKey: d.Get("private_key").(string), + nameProp, err := expandComputeSslCertificateName(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 + } + privateKeyProp, err := expandComputeSslCertificatePrivateKey(d.Get("private_key"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("private_key"); !isEmptyValue(reflect.ValueOf(privateKeyProp)) && (ok || !reflect.DeepEqual(v, privateKeyProp)) { + obj["privateKey"] = privateKeyProp } - if v, ok := d.GetOk("description"); ok { - cert.Description = v.(string) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/sslCertificates") + if err != nil { + return err } - op, err := config.clientCompute.SslCertificates.Insert( - project, cert).Do() + log.Printf("[DEBUG] Creating new SslCertificate: %#v", obj) + res, err := sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error creating SslCertificate: %s", err) + } + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") if err != nil { - return fmt.Errorf("Error creating ssl certificate: %s", err) + return fmt.Errorf("Error constructing id: %s", err) } + d.SetId(id) - err = computeOperationWait(config.clientCompute, op, project, "Creating SslCertificate") + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - d.SetId(cert.Name) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating SslCertificate", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create SslCertificate: %s", waitErr) + } + + log.Printf("[DEBUG] Finished creating SslCertificate %q: %#v", d.Id(), res) return resourceComputeSslCertificateRead(d, meta) } @@ -135,23 +181,41 @@ func resourceComputeSslCertificateCreate(d *schema.ResourceData, meta interface{ func resourceComputeSslCertificateRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - project, err := getProject(d, config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/sslCertificates/{{name}}") if err != nil { return err } - cert, err := config.clientCompute.SslCertificates.Get( - project, d.Id()).Do() + res, err := sendRequest(config, "GET", url, nil) if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("SSL Certificate %q", d.Get("name").(string))) + return handleNotFoundError(err, d, fmt.Sprintf("ComputeSslCertificate %q", d.Id())) } - d.Set("self_link", cert.SelfLink) - d.Set("certificate_id", strconv.FormatUint(cert.Id, 10)) - d.Set("description", cert.Description) - d.Set("name", cert.Name) - d.Set("certificate", cert.Certificate) - d.Set("project", project) + if err := d.Set("certificate", flattenComputeSslCertificateCertificate(res["certificate"])); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeSslCertificateCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + if err := d.Set("description", flattenComputeSslCertificateDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + if err := d.Set("certificate_id", flattenComputeSslCertificateCertificate_id(res["id"])); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + if err := d.Set("name", flattenComputeSslCertificateName(res["name"])); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading SslCertificate: %s", err) + } return nil } @@ -159,22 +223,108 @@ func resourceComputeSslCertificateRead(d *schema.ResourceData, meta interface{}) func resourceComputeSslCertificateDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - project, err := getProject(d, config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/sslCertificates/{{name}}") if err != nil { return err } - op, err := config.clientCompute.SslCertificates.Delete( - project, d.Id()).Do() + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting SslCertificate %q", d.Id()) + res, err := sendRequest(config, "DELETE", url, obj) + if err != nil { + return handleNotFoundError(err, d, "SslCertificate") + } + + project, err := getProject(d, config) + if err != nil { + return err + } + op := &compute.Operation{} + err = Convert(res, op) if err != nil { - return fmt.Errorf("Error deleting ssl certificate: %s", err) + return err } - err = computeOperationWait(config.clientCompute, op, project, "Deleting SslCertificate") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting SslCertificate", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") + log.Printf("[DEBUG] Finished deleting SslCertificate %q: %#v", d.Id(), res) return nil } + +func resourceComputeSslCertificateImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/sslCertificates/(?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 flattenComputeSslCertificateCertificate(v interface{}) interface{} { + return v +} + +func flattenComputeSslCertificateCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeSslCertificateDescription(v interface{}) interface{} { + return v +} + +func flattenComputeSslCertificateCertificate_id(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 flattenComputeSslCertificateName(v interface{}) interface{} { + return v +} + +func flattenComputeSslCertificatePrivateKey(v interface{}) interface{} { + return v +} + +func expandComputeSslCertificateCertificate(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeSslCertificateDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeSslCertificateName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + var certName string + if v, ok := d.GetOk("name"); ok { + certName = v.(string) + } else if v, ok := d.GetOk("name_prefix"); ok { + certName = resource.PrefixedUniqueId(v.(string)) + } else { + certName = resource.UniqueId() + } + + // We need to get the {{name}} into schema to set the ID using ReplaceVars + d.Set("name", certName) + + return certName, nil +} + +func expandComputeSslCertificatePrivateKey(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/website/docs/r/compute_ssl_certificate.html.markdown b/website/docs/r/compute_ssl_certificate.html.markdown index 77213bce424..f8175764cf5 100644 --- a/website/docs/r/compute_ssl_certificate.html.markdown +++ b/website/docs/r/compute_ssl_certificate.html.markdown @@ -1,18 +1,35 @@ --- +# ---------------------------------------------------------------------------- +# +# *** 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_ssl_certificate" sidebar_current: "docs-google-compute-ssl-certificate" description: |- - Creates an SSL certificate resource necessary for HTTPS load balancing in GCE. + An SslCertificate resource, used for HTTPS load balancing. --- # google\_compute\_ssl\_certificate -Creates an SSL certificate resource necessary for HTTPS load balancing in GCE. -For more information see -[the official documentation](https://cloud.google.com/compute/docs/load-balancing/http/ssl-certificates) and -[API](https://cloud.google.com/compute/docs/reference/latest/sslCertificates). +An SslCertificate resource, used for HTTPS load balancing. This resource +provides a mechanism to upload an SSL key and certificate to +the load balancer to serve secure connections from the user. +To get more information about SslCertificate, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/sslCertificates) +* How-to Guides + * [Official Documentation](https://cloud.google.com/load-balancing/docs/ssl-certificates) ## Example Usage @@ -53,18 +70,17 @@ resource "google_compute_ssl_certificate" "default" { } } ``` - -## Using with Target HTTPS Proxies - -SSL certificates cannot be updated after creation. In order to apply the -specified configuration, Terraform will destroy the existing resource -and create a replacement. To effectively use an SSL certificate resource -with a [Target HTTPS Proxy resource][1], it's recommended to specify -`create_before_destroy` in a [lifecycle][2] block. Either omit the -Instance Template `name` attribute, specify a partial name with -`name_prefix`, or use [random_id][3] resource. Example: - ```hcl +// Using with Target HTTPS Proxies +// +// SSL certificates cannot be updated after creation. In order to apply +// the specified configuration, Terraform will destroy the existing +// resource and create a replacement. To effectively use an SSL +// certificate resource with a Target HTTPS Proxy resource, it's +// recommended to specify create_before_destroy in a lifecycle block. +// Either omit the Instance Template name attribute, specify a partial +// name with name_prefix, or use random_id resource. Example: + resource "google_compute_ssl_certificate" "default" { name_prefix = "my-certificate-" description = "a description" @@ -87,44 +103,68 @@ resource "google_compute_target_https_proxy" "my_proxy" { The following arguments are supported: -* `certificate` - (Required) A local certificate file in PEM format. The chain - may be at most 5 certs long, and must include at least one intermediate - cert. Changing this forces a new resource to be created. -* `private_key` - (Required) Write only private key in PEM format. - Changing this forces a new resource to be created. +* `certificate` - + (Required) + The certificate in PEM format. + The certificate chain must be no greater than 5 certs long. + The chain must include at least one intermediate cert. + +* `private_key` - + (Required) + The write-only private key in PEM format. + - - - -* `name` - (Optional) A unique name for the SSL certificate. If you leave - this blank, Terraform will auto-generate a unique name. -* `name_prefix` - (Optional) Creates a unique name beginning with the specified - prefix. Conflicts with `name`. +* `description` - + (Optional) + An optional description of this resource. + +* `name` - + (Optional) + 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. +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `description` - (Optional) An optional description of this resource. - Changing this forces a new resource to be created. -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. +* `name_prefix` - (Optional) Creates a unique name beginning with the + specified prefix. Conflicts with `name`. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: +In addition to the arguments listed above, the following computed attributes are exported: + -* `certificate_id` - A unique ID for the certificate, assigned by GCE. +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. +* `certificate_id` - + The unique identifier for the resource. * `self_link` - The URI of the created resource. -[1]: /docs/providers/google/r/compute_target_https_proxy.html -[2]: /docs/configuration/resources.html#lifecycle -[3]: /docs/providers/random/r/id.html + +## 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 -SSL certificate can be imported using the `name`, e.g. +SslCertificate can be imported using any of these accepted formats: ``` -$ terraform import google_compute_ssl_certificate.default my-certificate +$ terraform import google_compute_ssl_certificate.default projects/{{project}}/global/sslCertificates/{{name}} +$ terraform import google_compute_ssl_certificate.default {{project}}/{{name}} +$ terraform import google_compute_ssl_certificate.default {{name}} ```