diff --git a/.changelog/1444.txt b/.changelog/1444.txt new file mode 100644 index 0000000000..7c0540c268 --- /dev/null +++ b/.changelog/1444.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +cloudflare_zone_cache_variants +``` \ No newline at end of file diff --git a/cloudflare/provider.go b/cloudflare/provider.go index be56679382..652b0664d6 100644 --- a/cloudflare/provider.go +++ b/cloudflare/provider.go @@ -180,6 +180,7 @@ func Provider() *schema.Provider { "cloudflare_worker_script": resourceCloudflareWorkerScript(), "cloudflare_workers_kv_namespace": resourceCloudflareWorkersKVNamespace(), "cloudflare_workers_kv": resourceCloudflareWorkerKV(), + "cloudflare_zone_cache_variants": resourceCloudflareZoneCacheVariants(), "cloudflare_zone_dnssec": resourceCloudflareZoneDNSSEC(), "cloudflare_zone_lockdown": resourceCloudflareZoneLockdown(), "cloudflare_zone_settings_override": resourceCloudflareZoneSettingsOverride(), diff --git a/cloudflare/resource_cloudflare_zone_cache_variants.go b/cloudflare/resource_cloudflare_zone_cache_variants.go new file mode 100644 index 0000000000..133323e9e3 --- /dev/null +++ b/cloudflare/resource_cloudflare_zone_cache_variants.go @@ -0,0 +1,169 @@ +package cloudflare + +import ( + "context" + "fmt" + "log" + "strings" + + cloudflare "github.com/cloudflare/cloudflare-go" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareZoneCacheVariants() *schema.Resource { + return &schema.Resource{ + Schema: resourceCloudflareZoneCacheVariantsSchema(), + Create: resourceCloudflareZoneCacheVariantsUpdate, + Read: resourceCloudflareZoneCacheVariantsRead, + Update: resourceCloudflareZoneCacheVariantsUpdate, + Delete: resourceCloudflareZoneCacheVariantsDelete, + } +} + +func resourceCloudflareZoneCacheVariantsRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cloudflare.API) + + log.Printf("[INFO] Reading Zone Cache Variants in zone %q", d.Id()) + + zoneCacheVariants, err := client.ZoneCacheVariants(context.Background(), d.Id()) + + if err != nil { + if strings.Contains(err.Error(), "HTTP status 404") { + log.Printf("[INFO] Zone Cache Variants for zone %q not found", d.Id()) + d.SetId("") + return nil + } else { + return fmt.Errorf("Error reading cache variants for zone %q: %w", d.Id(), err) + } + } + + value := zoneCacheVariants.Value + + if err := d.Set("avif", value.Avif); err != nil { + return fmt.Errorf("failed to set avif: %w", err) + } + + if err := d.Set("bmp", value.Bmp); err != nil { + return fmt.Errorf("failed to set bmp: %w", err) + } + + if err := d.Set("gif", value.Gif); err != nil { + return fmt.Errorf("failed to set gif: %w", err) + } + + if err := d.Set("jpeg", value.Jpeg); err != nil { + return fmt.Errorf("failed to set jpeg: %w", err) + } + + if err := d.Set("jpg", value.Jpg); err != nil { + return fmt.Errorf("failed to set jpg: %w", err) + } + + if err := d.Set("jp2", value.Jp2); err != nil { + return fmt.Errorf("failed to set jp2: %w", err) + } + + if err := d.Set("jpg2", value.Jpg2); err != nil { + return fmt.Errorf("failed to set jpg2: %w", err) + } + + if err := d.Set("png", value.Png); err != nil { + return fmt.Errorf("failed to set png: %w", err) + } + + if err := d.Set("tif", value.Tif); err != nil { + return fmt.Errorf("failed to set tif: %w", err) + } + + if err := d.Set("tiff", value.Tiff); err != nil { + return fmt.Errorf("failed to set tiff: %w", err) + } + + if err := d.Set("webp", value.Webp); err != nil { + return fmt.Errorf("failed to set webp: %w", err) + } + + return nil +} + +func resourceCloudflareZoneCacheVariantsUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cloudflare.API) + + zoneID := d.Get("zone_id").(string) + d.SetId(zoneID) + + variantsValue := cacheVariantsValuesFromResource(d) + log.Printf("[INFO] Setting Zone Cache Variants to struct: %+v for zone ID: %q", variantsValue, d.Id()) + + _, err := client.UpdateZoneCacheVariants(context.Background(), d.Id(), variantsValue) + + if err != nil { + return fmt.Errorf("error setting cache variants for zone %q: %w", d.Id(), err) + } + + return resourceCloudflareZoneCacheVariantsRead(d, meta) +} + +func resourceCloudflareZoneCacheVariantsDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cloudflare.API) + + log.Printf("[INFO] Deleting Zone Cache Variants for zone ID: %q", d.Id()) + + err := client.DeleteZoneCacheVariants(context.Background(), d.Id()) + + if err != nil { + return fmt.Errorf("error deleting cache variants for zone %v: %w", d.Id(), err) + } + + return nil +} + +func cacheVariantsValuesFromResource(d *schema.ResourceData) cloudflare.ZoneCacheVariantsValues { + variantsValue := cloudflare.ZoneCacheVariantsValues{} + + if value, ok := d.GetOk("avif"); ok { + variantsValue.Avif = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("bmp"); ok { + variantsValue.Bmp = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("gif"); ok { + variantsValue.Gif = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("jpeg"); ok { + variantsValue.Jpeg = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("jpg"); ok { + variantsValue.Jpg = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("jp2"); ok { + variantsValue.Jp2 = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("jpg2"); ok { + variantsValue.Jpg2 = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("png"); ok { + variantsValue.Png = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("tif"); ok { + variantsValue.Tif = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("tiff"); ok { + variantsValue.Tiff = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + if value, ok := d.GetOk("webp"); ok { + variantsValue.Webp = expandInterfaceToStringList(value.(*schema.Set).List()) + } + + return variantsValue +} diff --git a/cloudflare/resource_cloudflare_zone_cache_variants_test.go b/cloudflare/resource_cloudflare_zone_cache_variants_test.go new file mode 100644 index 0000000000..76a7c8c0a1 --- /dev/null +++ b/cloudflare/resource_cloudflare_zone_cache_variants_test.go @@ -0,0 +1,147 @@ +package cloudflare + +import ( + "context" + "fmt" + "log" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("cloudflare_zone_cache_variants", &resource.Sweeper{ + Name: "cloudflare_zone_cache_variants", + F: testSweepCloudflareZoneCacheVariants, + }) +} + +func testSweepCloudflareZoneCacheVariants(r string) error { + client, clientErr := sharedClient() + if clientErr != nil { + log.Printf("[ERROR] Failed to create Cloudflare client: %s", clientErr) + } + + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + log.Printf("[INFO] Deleting Zone Cache Variants for zone: %q", zoneID) + err := client.DeleteZoneCacheVariants(context.Background(), zoneID) + + if err != nil { + log.Printf("[ERROR] Failed to delete Zone Cache Variants for zone %q: %v", zoneID, err) + return err + } + + return nil +} + +func TestAccCloudflareZoneCacheVariants_OneExt(t *testing.T) { + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_zone_cache_variants.%s", rnd) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareZoneCacheVariants_OneExt(zoneID, rnd), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "id", zoneID), + resource.TestCheckResourceAttr(name, "zone_id", zoneID), + resource.TestCheckResourceAttr(name, "avif.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "avif.*", "image/avif"), + resource.TestCheckTypeSetElemAttr(name, "avif.*", "image/webp"), + resource.TestCheckNoResourceAttr(name, "bmp.#"), + resource.TestCheckNoResourceAttr(name, "gif.#"), + resource.TestCheckNoResourceAttr(name, "jpeg.#"), + resource.TestCheckNoResourceAttr(name, "jpg.#"), + resource.TestCheckNoResourceAttr(name, "jp2.#"), + resource.TestCheckNoResourceAttr(name, "jpg2.#"), + resource.TestCheckNoResourceAttr(name, "png.#"), + resource.TestCheckNoResourceAttr(name, "tif.#"), + resource.TestCheckNoResourceAttr(name, "tiff.#"), + resource.TestCheckNoResourceAttr(name, "webp.#"), + ), + }, + }, + }) +} + +func TestAccCloudflareZoneCacheVariants_AllExt(t *testing.T) { + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_zone_cache_variants.%s", rnd) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareZoneCacheVariants_AllExt(zoneID, rnd), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "id", zoneID), + resource.TestCheckResourceAttr(name, "zone_id", zoneID), + resource.TestCheckResourceAttr(name, "avif.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "avif.*", "image/avif"), + resource.TestCheckTypeSetElemAttr(name, "avif.*", "image/webp"), + resource.TestCheckResourceAttr(name, "bmp.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "bmp.*", "image/bmp"), + resource.TestCheckTypeSetElemAttr(name, "bmp.*", "image/webp"), + resource.TestCheckResourceAttr(name, "gif.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "gif.*", "image/gif"), + resource.TestCheckTypeSetElemAttr(name, "gif.*", "image/webp"), + resource.TestCheckResourceAttr(name, "jpeg.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "jpeg.*", "image/jpeg"), + resource.TestCheckTypeSetElemAttr(name, "jpeg.*", "image/webp"), + resource.TestCheckResourceAttr(name, "jpg.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "jpg.*", "image/jpg"), + resource.TestCheckTypeSetElemAttr(name, "jpg.*", "image/webp"), + resource.TestCheckResourceAttr(name, "jp2.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "jp2.*", "image/jp2"), + resource.TestCheckTypeSetElemAttr(name, "jp2.*", "image/webp"), + resource.TestCheckResourceAttr(name, "jpg2.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "jpg2.*", "image/jpg2"), + resource.TestCheckTypeSetElemAttr(name, "jpg2.*", "image/webp"), + resource.TestCheckResourceAttr(name, "png.#", "1"), + resource.TestCheckTypeSetElemAttr(name, "png.*", "image/png"), + resource.TestCheckResourceAttr(name, "tif.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "tif.*", "image/tif"), + resource.TestCheckTypeSetElemAttr(name, "tif.*", "image/webp"), + resource.TestCheckResourceAttr(name, "tiff.#", "2"), + resource.TestCheckTypeSetElemAttr(name, "tiff.*", "image/tiff"), + resource.TestCheckTypeSetElemAttr(name, "tiff.*", "image/webp"), + resource.TestCheckResourceAttr(name, "webp.#", "1"), + resource.TestCheckTypeSetElemAttr(name, "webp.*", "image/webp"), + ), + }, + }, + }) +} + +func testAccCloudflareZoneCacheVariants_OneExt(zoneID, name string) string { + return fmt.Sprintf(` + resource "cloudflare_zone_cache_variants" "%[2]s" { + zone_id = "%[1]s" + avif = ["image/avif", "image/webp"] + }`, zoneID, name) +} + +func testAccCloudflareZoneCacheVariants_AllExt(zoneID, name string) string { + return fmt.Sprintf(` + resource "cloudflare_zone_cache_variants" "%[2]s" { + zone_id = "%[1]s" + avif = ["image/avif", "image/webp"] + bmp = ["image/bmp", "image/webp"] + gif = ["image/gif", "image/webp"] + jpeg = ["image/jpeg", "image/webp"] + jpg = ["image/jpg", "image/webp"] + jp2 = ["image/jp2", "image/webp"] + jpg2 = ["image/jpg2", "image/webp"] + png = ["image/png"] + tif = ["image/tif", "image/webp"] + tiff = ["image/tiff", "image/webp"] + webp = ["image/webp"] + }`, zoneID, name) +} diff --git a/cloudflare/schema_cloudflare_zone_cache_variants.go b/cloudflare/schema_cloudflare_zone_cache_variants.go new file mode 100644 index 0000000000..cc3a455668 --- /dev/null +++ b/cloudflare/schema_cloudflare_zone_cache_variants.go @@ -0,0 +1,37 @@ +package cloudflare + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareZoneCacheVariantsExtensionSchema() *schema.Schema { + return &schema.Schema{ + MinItems: 1, + Optional: true, + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + } +} + +func resourceCloudflareZoneCacheVariantsSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "zone_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "avif": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "bmp": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "gif": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "jpeg": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "jpg": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "jpg2": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "jp2": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "png": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "tiff": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "tif": resourceCloudflareZoneCacheVariantsExtensionSchema(), + "webp": resourceCloudflareZoneCacheVariantsExtensionSchema(), + } +}