From b635fe4577c2b9bd82cd74dda1350d13d5d98830 Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Tue, 22 Nov 2022 22:54:52 +0100 Subject: [PATCH 1/9] First version --- .changelog/2047.txt | 3 +++ ...source_cloudflare_origin_ca_certificate.go | 26 +++++++++++++++++++ ...schema_cloudflare_origin_ca_certificate.go | 9 +++++++ 3 files changed, 38 insertions(+) create mode 100644 .changelog/2047.txt diff --git a/.changelog/2047.txt b/.changelog/2047.txt new file mode 100644 index 0000000000..b3e6bc3ea1 --- /dev/null +++ b/.changelog/2047.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_origin_ca_certificate: add logic to renew certificate and add a new flag to set if we should renew earlier +``` \ No newline at end of file diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index ffb172cc99..a2d262b8fa 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -13,6 +13,8 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + ) func resourceCloudflareOriginCACertificate() *schema.Resource { @@ -25,9 +27,31 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + CustomizeDiff: customdiff.Sequence( + customdiff.ForceNewIf("requires_renew", mustRenew), + ), } } +func mustRenew(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { + // Check when the cert will expire + expiresonRaw := d.Get("expires_on") + if expiresonRaw == nil { + return false + } + expireson, _ := time.Parse(time.RFC3339, expiresonRaw.(string)) + + // Calculate when we should renew + earlyExpiration := expireson.AddDate( 0, 0, -1 * d.Get("early_renewal_days").(int) ) + + if time.Now().After(earlyExpiration) { + d.SetNew("requires_renew", true) + return true + } + + return false +} + func resourceCloudflareOriginCACertificateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*cloudflare.API) @@ -94,6 +118,8 @@ func resourceCloudflareOriginCACertificateRead(ctx context.Context, d *schema.Re d.Set("hostnames", hostnames) d.Set("request_type", cert.RequestType) + d.Set("requires_renew", false) + certBlock, _ := pem.Decode([]byte(cert.Certificate)) if certBlock == nil { return diag.FromErr(fmt.Errorf("error decoding OriginCACertificate %q: %w", certID, err)) diff --git a/internal/provider/schema_cloudflare_origin_ca_certificate.go b/internal/provider/schema_cloudflare_origin_ca_certificate.go index cc5ef40c38..d0fad9e492 100644 --- a/internal/provider/schema_cloudflare_origin_ca_certificate.go +++ b/internal/provider/schema_cloudflare_origin_ca_certificate.go @@ -40,5 +40,14 @@ func resourceCloudflareOriginCACertificateSchema() map[string]*schema.Schema { Computed: true, ValidateFunc: validation.IntInSlice([]int{7, 30, 90, 365, 730, 1095, 5475}), }, + "early_renewal_days": { + Type: schema.TypeInt, + Optional: true, + }, + "requires_renew": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, } } From 03e6618e5b2062bf7dfd21bcf277f661148504f7 Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Tue, 22 Nov 2022 23:00:34 +0100 Subject: [PATCH 2/9] Renaming changelog --- .changelog/{2047.txt => 2048.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{2047.txt => 2048.txt} (100%) diff --git a/.changelog/2047.txt b/.changelog/2048.txt similarity index 100% rename from .changelog/2047.txt rename to .changelog/2048.txt From b368a6ffb1c6f6f16cd38dac8ce0ee0c734de76d Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Wed, 23 Nov 2022 07:16:50 +0100 Subject: [PATCH 3/9] Fixing lint issues --- .../resource_cloudflare_origin_ca_certificate.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index d2c2d8a01d..c0af25eecb 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -12,9 +12,8 @@ import ( cloudflare "github.com/cloudflare/cloudflare-go" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" - + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceCloudflareOriginCACertificate() *schema.Resource { @@ -36,19 +35,22 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { func mustRenew(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { // Check when the cert will expire - expiresonRaw := d.Get("expires_on") + expiresonRaw := d.Get("expires_on") if expiresonRaw == nil { return false - } + } expireson, _ := time.Parse(time.RFC3339, expiresonRaw.(string)) // Calculate when we should renew - earlyExpiration := expireson.AddDate( 0, 0, -1 * d.Get("early_renewal_days").(int) ) + earlyExpiration := expireson.AddDate(0, 0, -1*d.Get("early_renewal_days").(int)) if time.Now().After(earlyExpiration) { - d.SetNew("requires_renew", true) + err := d.SetNew("requires_renew", true) + if err != nil { + return diag.FromErr(fmt.Errorf("error setting to renew a certificte about to expire: %w", err)) + } return true - } + } return false } From 9bfe4ab81e3a4f61ffef296b4055cecaa218c508 Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Wed, 23 Nov 2022 07:31:25 +0100 Subject: [PATCH 4/9] Fix error handling --- .../provider/resource_cloudflare_origin_ca_certificate.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index c0af25eecb..aa608ad970 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -33,7 +33,7 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { } } -func mustRenew(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { +func mustRenew(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool { // Check when the cert will expire expiresonRaw := d.Get("expires_on") if expiresonRaw == nil { @@ -47,7 +47,8 @@ func mustRenew(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool if time.Now().After(earlyExpiration) { err := d.SetNew("requires_renew", true) if err != nil { - return diag.FromErr(fmt.Errorf("error setting to renew a certificte about to expire: %w", err)) + tflog.Warn(ctx, fmt.Sprintf("error creating origin certificate: %w", err)) + return false } return true } From 4cb497236dd0fc2c3b5df161730c3ca5a59b8f3a Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Wed, 23 Nov 2022 07:44:04 +0100 Subject: [PATCH 5/9] Ling issues in schema file --- internal/provider/schema_cloudflare_origin_ca_certificate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/schema_cloudflare_origin_ca_certificate.go b/internal/provider/schema_cloudflare_origin_ca_certificate.go index 80e3dd850f..da7cc8e66a 100644 --- a/internal/provider/schema_cloudflare_origin_ca_certificate.go +++ b/internal/provider/schema_cloudflare_origin_ca_certificate.go @@ -51,7 +51,7 @@ func resourceCloudflareOriginCACertificateSchema() map[string]*schema.Schema { }, "early_renewal_days": { Type: schema.TypeInt, - Optional: true, + Optional: true, }, "requires_renew": { Type: schema.TypeBool, From 3098416be30ddcdf8dc10e7b27f202fd0bdb5279 Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Wed, 23 Nov 2022 09:42:48 +0100 Subject: [PATCH 6/9] Change how to format error --- internal/provider/resource_cloudflare_origin_ca_certificate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index aa608ad970..c2ef215b2e 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -47,7 +47,7 @@ func mustRenew(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bo if time.Now().After(earlyExpiration) { err := d.SetNew("requires_renew", true) if err != nil { - tflog.Warn(ctx, fmt.Sprintf("error creating origin certificate: %w", err)) + tflog.Warn(ctx, fmt.Sprintf("error creating origin certificate: %s", err)) return false } return true From dd2ffb2ce51c0ee9f443d0e231111a2c86b134d4 Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Wed, 23 Nov 2022 11:08:08 +0100 Subject: [PATCH 7/9] Simplified the code --- .../resource_cloudflare_origin_ca_certificate.go | 13 ++++++------- .../schema_cloudflare_origin_ca_certificate.go | 5 ----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index c2ef215b2e..c006fa0208 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -20,14 +20,14 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { return &schema.Resource{ Schema: resourceCloudflareOriginCACertificateSchema(), CreateContext: resourceCloudflareOriginCACertificateCreate, - UpdateContext: resourceCloudflareOriginCACertificateCreate, + UpdateContext: resourceCloudflareOriginCACertificateRead, ReadContext: resourceCloudflareOriginCACertificateRead, DeleteContext: resourceCloudflareOriginCACertificateDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, CustomizeDiff: customdiff.Sequence( - customdiff.ForceNewIf("requires_renew", mustRenew), + customdiff.ForceNewIf("expires_on", mustRenew), ), Description: "Provides a Cloudflare Origin CA certificate used to protect traffic to your origin without involving a third party Certificate Authority.", } @@ -36,7 +36,7 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { func mustRenew(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool { // Check when the cert will expire expiresonRaw := d.Get("expires_on") - if expiresonRaw == nil { + if (expiresonRaw == nil) || (expiresonRaw == "") { return false } expireson, _ := time.Parse(time.RFC3339, expiresonRaw.(string)) @@ -45,9 +45,10 @@ func mustRenew(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bo earlyExpiration := expireson.AddDate(0, 0, -1*d.Get("early_renewal_days").(int)) if time.Now().After(earlyExpiration) { - err := d.SetNew("requires_renew", true) + tflog.Info(ctx, fmt.Sprintf("We will renew the certificate as we passed the expected date (%s)", earlyExpiration)) + err := d.SetNewComputed("expires_on") if err != nil { - tflog.Warn(ctx, fmt.Sprintf("error creating origin certificate: %s", err)) + tflog.Warn(ctx, fmt.Sprintf("error setting to renew the certificate: %s", err)) return false } return true @@ -122,8 +123,6 @@ func resourceCloudflareOriginCACertificateRead(ctx context.Context, d *schema.Re d.Set("hostnames", hostnames) d.Set("request_type", cert.RequestType) - d.Set("requires_renew", false) - certBlock, _ := pem.Decode([]byte(cert.Certificate)) if certBlock == nil { return diag.FromErr(fmt.Errorf("error decoding OriginCACertificate %q: %w", certID, err)) diff --git a/internal/provider/schema_cloudflare_origin_ca_certificate.go b/internal/provider/schema_cloudflare_origin_ca_certificate.go index da7cc8e66a..3895717236 100644 --- a/internal/provider/schema_cloudflare_origin_ca_certificate.go +++ b/internal/provider/schema_cloudflare_origin_ca_certificate.go @@ -53,10 +53,5 @@ func resourceCloudflareOriginCACertificateSchema() map[string]*schema.Schema { Type: schema.TypeInt, Optional: true, }, - "requires_renew": { - Type: schema.TypeBool, - Optional: true, - Computed: true, - }, } } From 1ac0dafad86cf09fdc515df07c4468b78745321f Mon Sep 17 00:00:00 2001 From: Fabio Peruzzo Barbosa Date: Fri, 25 Nov 2022 07:23:38 +0100 Subject: [PATCH 8/9] Restoring UpdateContext --- internal/provider/resource_cloudflare_origin_ca_certificate.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index 8b4deac44f..6a1f13cefd 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -21,6 +21,7 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { Schema: resourceCloudflareOriginCACertificateSchema(), CreateContext: resourceCloudflareOriginCACertificateCreate, ReadContext: resourceCloudflareOriginCACertificateRead, + UpdateContext: resourceCloudflareOriginCACertificateRead, DeleteContext: resourceCloudflareOriginCACertificateDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, From b3526c804f0f2a3c78ac661d1ce1258ec94ee3e9 Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Mon, 28 Nov 2022 13:15:36 +1100 Subject: [PATCH 9/9] `make docs` --- docs/resources/origin_ca_certificate.md | 3 ++- internal/provider/provider_test.go | 5 +++++ .../provider/resource_cloudflare_origin_ca_certificate.go | 2 +- .../resource_cloudflare_origin_ca_certificate_test.go | 1 - .../provider/schema_cloudflare_origin_ca_certificate.go | 7 ++++--- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/resources/origin_ca_certificate.md b/docs/resources/origin_ca_certificate.md index 8f87d7a8d3..6861599f76 100644 --- a/docs/resources/origin_ca_certificate.md +++ b/docs/resources/origin_ca_certificate.md @@ -48,7 +48,8 @@ resource "cloudflare_origin_ca_certificate" "example" { ### Optional -- `csr` (String) The Certificate Signing Request. Must be newline-encoded. +- `csr` (String) The Certificate Signing Request. Must be newline-encoded. **Modifying this attribute will force creation of a new resource.** +- `min_days_for_renewal` (Number) Number of days prior to the expiry to trigger a renewal of the certificate if a Terraform operation is run. - `requested_validity` (Number) The number of days for which the certificate should be valid. Available values: `7`, `30`, `90`, `365`, `730`, `1095`, `5475`. **Modifying this attribute will force creation of a new resource.** ### Read-Only diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 034015f0e6..c197c0bff0 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -125,6 +125,11 @@ func testAccPreCheckApiUserServiceKey(t *testing.T) { if v := os.Getenv("CLOUDFLARE_API_USER_SERVICE_KEY"); v == "" { t.Fatal("CLOUDFLARE_API_USER_SERVICE_KEY must be set for acceptance tests") } + + err := testAccProvider.Configure(context.Background(), terraform.NewResourceConfigRaw(nil)) + if err != nil { + t.Fatal(err) + } } func testAccPreCheckDomain(t *testing.T) { diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate.go b/internal/provider/resource_cloudflare_origin_ca_certificate.go index 6a1f13cefd..f6d0c740d7 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -42,7 +42,7 @@ func mustRenew(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bo expireson, _ := time.Parse(time.RFC3339, expiresonRaw.(string)) // Calculate when we should renew - earlyExpiration := expireson.AddDate(0, 0, -1*d.Get("early_renewal_days").(int)) + earlyExpiration := expireson.AddDate(0, 0, -1*d.Get("min_days_for_renewal").(int)) if time.Now().After(earlyExpiration) { tflog.Info(ctx, fmt.Sprintf("We will renew the certificate as we passed the expected date (%s)", earlyExpiration)) diff --git a/internal/provider/resource_cloudflare_origin_ca_certificate_test.go b/internal/provider/resource_cloudflare_origin_ca_certificate_test.go index a3adf0f621..9766e021c9 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate_test.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate_test.go @@ -33,7 +33,6 @@ func TestAccCloudflareOriginCACertificate_Basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { - testAccPreCheck(t) testAccPreCheckApiUserServiceKey(t) }, ProviderFactories: providerFactories, diff --git a/internal/provider/schema_cloudflare_origin_ca_certificate.go b/internal/provider/schema_cloudflare_origin_ca_certificate.go index f226dc711d..7fe1dd91bc 100644 --- a/internal/provider/schema_cloudflare_origin_ca_certificate.go +++ b/internal/provider/schema_cloudflare_origin_ca_certificate.go @@ -50,9 +50,10 @@ func resourceCloudflareOriginCACertificateSchema() map[string]*schema.Schema { ValidateFunc: validation.IntInSlice([]int{7, 30, 90, 365, 730, 1095, 5475}), Description: fmt.Sprintf("The number of days for which the certificate should be valid. %s", renderAvailableDocumentationValuesIntSlice([]int{7, 30, 90, 365, 730, 1095, 5475})), }, - "early_renewal_days": { - Type: schema.TypeInt, - Optional: true, + "min_days_for_renewal": { + Type: schema.TypeInt, + Optional: true, + Description: "Number of days prior to the expiry to trigger a renewal of the certificate if a Terraform operation is run.", }, } }