diff --git a/.changelog/2048.txt b/.changelog/2048.txt new file mode 100644 index 0000000000..b3e6bc3ea1 --- /dev/null +++ b/.changelog/2048.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/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 37dc0a54b7..f6d0c740d7 100644 --- a/internal/provider/resource_cloudflare_origin_ca_certificate.go +++ b/internal/provider/resource_cloudflare_origin_ca_certificate.go @@ -12,6 +12,7 @@ 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/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -20,14 +21,42 @@ func resourceCloudflareOriginCACertificate() *schema.Resource { Schema: resourceCloudflareOriginCACertificateSchema(), CreateContext: resourceCloudflareOriginCACertificateCreate, ReadContext: resourceCloudflareOriginCACertificateRead, + UpdateContext: resourceCloudflareOriginCACertificateRead, DeleteContext: resourceCloudflareOriginCACertificateDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, + CustomizeDiff: customdiff.Sequence( + 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.", } } +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) || (expiresonRaw == "") { + return false + } + expireson, _ := time.Parse(time.RFC3339, expiresonRaw.(string)) + + // Calculate when we should renew + 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)) + err := d.SetNewComputed("expires_on") + if err != nil { + tflog.Warn(ctx, fmt.Sprintf("error setting to renew the certificate: %s", err)) + return false + } + return true + } + + return false +} + func resourceCloudflareOriginCACertificateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*cloudflare.API) 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 850f032922..7fe1dd91bc 100644 --- a/internal/provider/schema_cloudflare_origin_ca_certificate.go +++ b/internal/provider/schema_cloudflare_origin_ca_certificate.go @@ -50,5 +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})), }, + "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.", + }, } }