Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new field desired_state to manage CertificateAuthority state #11638

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/5934.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
privateca: add a new field `desired_state` to manage CertificateAuthority state.
```
124 changes: 106 additions & 18 deletions google/resource_privateca_certificate_authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package google

import (
"context"
"fmt"
"log"
"reflect"
Expand All @@ -24,6 +25,31 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourcePrivateCaCACustomDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error {
if diff.HasChange("desired_state") {
_, new := diff.GetChange("desired_state")

if isNewResource(diff) {
if diff.Get("type").(string) == "SUBORDINATE" {
return fmt.Errorf("`desired_state` can not be specified when creating a SUBORDINATE CA")
}
if new.(string) != "STAGED" && new.(string) != "ENABLED" {
return fmt.Errorf("`desired_state` can only be set to `STAGED` or `ENABLED` when creating a new CA")
}
} else {
if new == "STAGED" && diff.Get("state") != new {
return fmt.Errorf("Field `desired_state` can only be set to `STAGED` when creating a new CA")
}
}
}
return nil
}

func isNewResource(diff *schema.ResourceDiff) bool {
name := diff.Get("name")
return name.(string) == ""
}

func resourcePrivatecaCertificateAuthority() *schema.Resource {
return &schema.Resource{
Create: resourcePrivatecaCertificateAuthorityCreate,
Expand All @@ -41,6 +67,8 @@ func resourcePrivatecaCertificateAuthority() *schema.Resource {
Delete: schema.DefaultTimeout(20 * time.Minute),
},

CustomizeDiff: resourcePrivateCaCACustomDiff,

Schema: map[string]*schema.Schema{
"certificate_authority_id": {
Type: schema.TypeString,
Expand Down Expand Up @@ -601,6 +629,10 @@ fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045
Optional: true,
Default: true,
},
"desired_state": {
Type: schema.TypeString,
Optional: true,
},
"project": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -719,24 +751,30 @@ func resourcePrivatecaCertificateAuthorityCreate(d *schema.ResourceData, meta in
}
d.SetId(id)

if d.Get("type").(string) != "SUBORDINATE" {
url, err = replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/caPools/{{pool}}/certificateAuthorities/{{certificate_authority_id}}:enable")
if err != nil {
return err
}

log.Printf("[DEBUG] Enabling CertificateAuthority: %#v", obj)

res, err = sendRequest(config, "POST", billingProject, url, userAgent, nil)
if err != nil {
return fmt.Errorf("Error enabling CertificateAuthority: %s", err)
}

err = privatecaOperationWaitTimeWithResponse(
config, res, &opRes, project, "Enabling CertificateAuthority", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
return fmt.Errorf("Error waiting to enable CertificateAuthority: %s", err)
staged := d.Get("type").(string) == "SELF_SIGNED"

// Enable the CA if `desired_state` is unspecified or specified as `ENABLED`.
if p, ok := d.GetOk("desired_state"); !ok || p.(string) == "ENABLED" {
// Skip enablement on SUBORDINATE CA for backward compatible.
if staged {
url, err = replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/caPools/{{pool}}/certificateAuthorities/{{certificate_authority_id}}:enable")
if err != nil {
return err
}

log.Printf("[DEBUG] Enabling CertificateAuthority: %#v", obj)

res, err = sendRequest(config, "POST", billingProject, url, userAgent, nil)
if err != nil {
return fmt.Errorf("Error enabling CertificateAuthority: %s", err)
}

err = privatecaOperationWaitTimeWithResponse(
config, res, &opRes, project, "Enabling CertificateAuthority", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
return fmt.Errorf("Error waiting to enable CertificateAuthority: %s", err)
}
}
}

Expand Down Expand Up @@ -877,6 +915,56 @@ func resourcePrivatecaCertificateAuthorityUpdate(d *schema.ResourceData, meta in
if err != nil {
return err
}
if d.HasChange("desired_state") {
// Currently, most CA state update operations are not idempotent.
// Try to change state only if the current `state` does not match the `desired_state`.
if p, ok := d.GetOk("desired_state"); ok && p.(string) != d.Get("state").(string) {
switch p.(string) {
case "ENABLED":
enableUrl, err := replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/caPools/{{pool}}/certificateAuthorities/{{certificate_authority_id}}:enable")
if err != nil {
return err
}

log.Printf("[DEBUG] Enabling CA: %#v", obj)

res, err := sendRequest(config, "POST", billingProject, enableUrl, userAgent, nil)
if err != nil {
return fmt.Errorf("Error enabling CA: %s", err)
}

var opRes map[string]interface{}
err = privatecaOperationWaitTimeWithResponse(
config, res, &opRes, project, "Enabling CA", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
return fmt.Errorf("Error waiting to enable CA: %s", err)
}
case "DISABLED":
disableUrl, err := replaceVars(d, config, "{{PrivatecaBasePath}}projects/{{project}}/locations/{{location}}/caPools/{{pool}}/certificateAuthorities/{{certificate_authority_id}}:disable")
if err != nil {
return err
}

log.Printf("[DEBUG] Disabling CA: %#v", obj)

dRes, err := sendRequest(config, "POST", billingProject, disableUrl, userAgent, nil)
if err != nil {
return fmt.Errorf("Error disabling CA: %s", err)
}

var opRes map[string]interface{}
err = privatecaOperationWaitTimeWithResponse(
config, dRes, &opRes, project, "Disabling CA", userAgent,
d.Timeout(schema.TimeoutDelete))
if err != nil {
return fmt.Errorf("Error waiting to disable CA: %s", err)
}
default:
return fmt.Errorf("Unsupported value in field `desired_state`")
}
}
}

// err == nil indicates that the billing_project value was found
if bp, err := getBillingProject(d, config); err == nil {
Expand Down
Loading