From c9f6e274aff1102487299ecc53a3949d8dec9adb Mon Sep 17 00:00:00 2001 From: Javier Ramos Date: Thu, 29 Aug 2024 11:07:01 +0200 Subject: [PATCH 1/3] fix: add nil check for ZoneSettingsOverrideUpgrade --- .changelog/3829.txt | 3 +++ .../resource_cloudflare_zone_settings_override_migrate.go | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changelog/3829.txt diff --git a/.changelog/3829.txt b/.changelog/3829.txt new file mode 100644 index 0000000000..e31e8efbd0 --- /dev/null +++ b/.changelog/3829.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/cloudflare_zone_settings_override: fix migration process with nil initial_settings +``` diff --git a/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go index fa71186a8b..8687b2a66f 100644 --- a/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go +++ b/internal/sdkv2provider/resource_cloudflare_zone_settings_override_migrate.go @@ -43,7 +43,9 @@ func resourceCloudflareZoneSettingsOverrideStateUpgradeV1( } upgrade := func(state map[string]interface{}, name string) map[string]interface{} { - delete(state[name].([]interface{})[0].(map[string]interface{}), "mobile_redirect") + if val, ok := state[name]; ok && val != nil { + delete(state[name].([]interface{})[0].(map[string]interface{}), "mobile_redirect") + } return state } @@ -89,7 +91,9 @@ func resourceCloudflareZoneSettingsOverrideStateUpgradeV2( } upgrade := func(state map[string]interface{}, name string) map[string]interface{} { - delete(state[name].([]interface{})[0].(map[string]interface{}), "minify") + if val, ok := state[name]; ok && val != nil { + delete(state[name].([]interface{})[0].(map[string]interface{}), "minify") + } return state } From 5a34b1b62d7acf6f4e9ab5d722b1973d320e7575 Mon Sep 17 00:00:00 2001 From: Anthony Turcios Date: Thu, 29 Aug 2024 10:45:08 -0400 Subject: [PATCH 2/3] resource/rulesets: add "contains" support to custom cache key headers --- .changelog/3820.txt | 3 ++ docs/data-sources/rulesets.md | 1 + docs/resources/ruleset.md | 5 +++ .../resources/cloudflare_ruleset/resource.tf | 5 +++ internal/framework/service/rulesets/model.go | 7 ++-- .../framework/service/rulesets/resource.go | 16 ++++++++- .../service/rulesets/resource_test.go | 33 +++++++++++++++++++ internal/framework/service/rulesets/schema.go | 7 ++++ .../sdkv2provider/data_source_rulesets.go | 11 +++++++ 9 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 .changelog/3820.txt diff --git a/.changelog/3820.txt b/.changelog/3820.txt new file mode 100644 index 0000000000..d409a6437d --- /dev/null +++ b/.changelog/3820.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/rulesets: add "contains" support to custom cache key headers +``` diff --git a/docs/data-sources/rulesets.md b/docs/data-sources/rulesets.md index 951ea7acbb..19612f2bcb 100644 --- a/docs/data-sources/rulesets.md +++ b/docs/data-sources/rulesets.md @@ -191,6 +191,7 @@ Read-Only: - `check_presence` (List of String) - `exclude_origin` (Boolean) - `include` (List of String) +- `contains` (Map of String to List) diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index ba416709e9..d5766a454e 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -300,6 +300,11 @@ resource "cloudflare_ruleset" "cache_settings_example" { include = ["habc", "hdef"] check_presence = ["habc_t", "hdef_t"] exclude_origin = true + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } cookie { include = ["cabc", "cdef"] diff --git a/examples/resources/cloudflare_ruleset/resource.tf b/examples/resources/cloudflare_ruleset/resource.tf index f713cc09f7..7e30c6b559 100644 --- a/examples/resources/cloudflare_ruleset/resource.tf +++ b/examples/resources/cloudflare_ruleset/resource.tf @@ -275,6 +275,11 @@ resource "cloudflare_ruleset" "cache_settings_example" { include = ["habc", "hdef"] check_presence = ["habc_t", "hdef_t"] exclude_origin = true + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } cookie { include = ["cabc", "cdef"] diff --git a/internal/framework/service/rulesets/model.go b/internal/framework/service/rulesets/model.go index abacc3a645..8347104f71 100644 --- a/internal/framework/service/rulesets/model.go +++ b/internal/framework/service/rulesets/model.go @@ -196,9 +196,10 @@ type ActionParameterCacheKeyCustomKeyQueryStringModel struct { } type ActionParameterCacheKeyCustomKeyHeaderModel struct { - Include types.Set `tfsdk:"include"` - CheckPresence types.Set `tfsdk:"check_presence"` - ExcludeOrigin types.Bool `tfsdk:"exclude_origin"` + Include types.Set `tfsdk:"include"` + CheckPresence types.Set `tfsdk:"check_presence"` + ExcludeOrigin types.Bool `tfsdk:"exclude_origin"` + Contains map[string]types.Set `tfsdk:"contains"` } type ActionParameterCacheKeyCustomKeyCookieModel struct { diff --git a/internal/framework/service/rulesets/resource.go b/internal/framework/service/rulesets/resource.go index 7d55df5075..a5edb82f74 100644 --- a/internal/framework/service/rulesets/resource.go +++ b/internal/framework/service/rulesets/resource.go @@ -542,11 +542,20 @@ func toRulesetResourceModel(ctx context.Context, zoneID, accountID basetypes.Str } else { excludeOrigin = types.BoolNull() } - if len(include.Elements()) > 0 || len(checkPresence.Elements()) > 0 || excludeOrigin.ValueBool() { + contains := map[string]types.Set{} + for k, v := range ruleResponse.ActionParameters.CacheKey.CustomKey.Header.Contains { + set, _ := basetypes.NewSetValueFrom(ctx, types.StringType, v) + contains[k] = set + } + if len(include.Elements()) > 0 || len(checkPresence.Elements()) > 0 || excludeOrigin.ValueBool() || len(contains) > 0 { + if len(contains) == 0 { + contains = nil + } key.Header = []*ActionParameterCacheKeyCustomKeyHeaderModel{{ Include: include, CheckPresence: checkPresence, ExcludeOrigin: excludeOrigin, + Contains: contains, }} } } @@ -1174,6 +1183,10 @@ func (r *RulesModel) toRulesetRule(ctx context.Context) cfv1.RulesetRule { if len(ap.CacheKey[0].CustomKey[0].Header) > 0 { includeQueryList := expanders.StringSet(ctx, ap.CacheKey[0].CustomKey[0].Header[0].Include) checkPresenceList := expanders.StringSet(ctx, basetypes.SetValue(ap.CacheKey[0].CustomKey[0].Header[0].CheckPresence)) + containsMap := map[string][]string{} + for k, v := range ap.CacheKey[0].CustomKey[0].Header[0].Contains { + containsMap[k] = expanders.StringSet(ctx, v) + } customKey.Header = &cfv1.RulesetRuleActionParametersCustomKeyHeader{ RulesetRuleActionParametersCustomKeyFields: cfv1.RulesetRuleActionParametersCustomKeyFields{ @@ -1181,6 +1194,7 @@ func (r *RulesModel) toRulesetRule(ctx context.Context) cfv1.RulesetRule { CheckPresence: checkPresenceList, }, ExcludeOrigin: cfv1.BoolPtr(ap.CacheKey[0].CustomKey[0].Header[0].ExcludeOrigin.ValueBool()), + Contains: containsMap, } } diff --git a/internal/framework/service/rulesets/resource_test.go b/internal/framework/service/rulesets/resource_test.go index 786596f0a5..676ddfef6d 100644 --- a/internal/framework/service/rulesets/resource_test.go +++ b/internal/framework/service/rulesets/resource_test.go @@ -1875,6 +1875,9 @@ func TestAccCloudflareRuleset_CacheSettingsAllEnabled(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.check_presence.0", "habc_t"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.check_presence.1", "hdef_t"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.exclude_origin", "true"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.%", "3"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.*", "image/web"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.cookie.0.include.#", "2"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.cookie.0.include.0", "cabc"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.cookie.0.include.1", "cdef"), @@ -1950,6 +1953,7 @@ func TestAccCloudflareRuleset_CacheSettingsOnlyExludeOrigin(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.#", "0"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.check_presence.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.%", "0"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.exclude_origin", "true"), ), }, @@ -2580,6 +2584,9 @@ func TestAccCloudflareRuleset_CacheSettingsHandleDefaultHeaderExcludeOrigin(t *t resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.0", "x-test"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.1", "x-test2"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.exclude_origin", "false"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.%", "3"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.*", "image/web"), ), }, { @@ -2599,6 +2606,9 @@ func TestAccCloudflareRuleset_CacheSettingsHandleDefaultHeaderExcludeOrigin(t *t resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.0", "x-test"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.1", "x-test2"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.exclude_origin", "false"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.%", "3"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.*", "image/web"), ), }, { @@ -2618,6 +2628,9 @@ func TestAccCloudflareRuleset_CacheSettingsHandleDefaultHeaderExcludeOrigin(t *t resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.0", "x-test"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.include.1", "x-test2"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.exclude_origin", "true"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.%", "3"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "rules.0.action_parameters.0.cache_key.0.custom_key.0.header.0.contains.accept.*", "image/web"), ), }, }, @@ -4110,6 +4123,11 @@ func testAccCloudflareRulesetCacheSettingsAllEnabled(rnd, accountID, zoneID stri include = ["habc", "hdef"] check_presence = ["habc_t", "hdef_t"] exclude_origin = true + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } cookie { include = ["cabc", "cdef"] @@ -4786,6 +4804,11 @@ func testAccCloudflareRulesetCacheSettingsHandleDefaultHeaderExcludeOrigin(rnd, header { check_presence = ["x-forwarded-for"] include = ["x-test", "x-test2"] + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } } } @@ -4820,6 +4843,11 @@ func testAccCloudflareRulesetCacheSettingsHandleHeaderExcludeOriginSet(rnd, zone check_presence = ["x-forwarded-for"] include = ["x-test", "x-test2"] exclude_origin = true + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } } } @@ -4854,6 +4882,11 @@ func testAccCloudflareRulesetCacheSettingsHandleHeaderExcludeOriginFalse(rnd, zo check_presence = ["x-forwarded-for"] include = ["x-test", "x-test2"] exclude_origin = false + contains = { + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] + } } } } diff --git a/internal/framework/service/rulesets/schema.go b/internal/framework/service/rulesets/schema.go index f5e3114291..2b0712d7e6 100644 --- a/internal/framework/service/rulesets/schema.go +++ b/internal/framework/service/rulesets/schema.go @@ -643,6 +643,13 @@ func (r *RulesetResource) Schema(ctx context.Context, req resource.SchemaRequest defaults.DefaultBool(false), }, }, + "contains": schema.MapAttribute{ + ElementType: types.SetType{ + ElemType: types.StringType, + }, + Optional: true, + MarkdownDescription: "Dictionary of headers mapping to lists of values to check for presence in the custom key.", + }, }, }, Validators: []validator.List{ diff --git a/internal/sdkv2provider/data_source_rulesets.go b/internal/sdkv2provider/data_source_rulesets.go index 109948de0e..692a6d8f2a 100644 --- a/internal/sdkv2provider/data_source_rulesets.go +++ b/internal/sdkv2provider/data_source_rulesets.go @@ -766,6 +766,17 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema { Optional: true, Description: "Exclude the origin header from the custom key.", }, + "contains": { + Type: schema.TypeMap, + Optional: true, + Description: "Dictionary of headers mapping to lists of values to check for presence in the custom key.", + Elem: &schema.Schema{ + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, }, }, }, From 2a5cc4a952018936df135bb2afd72d81f047ef9f Mon Sep 17 00:00:00 2001 From: Jacob Bednarz Date: Fri, 30 Aug 2024 16:07:14 +1000 Subject: [PATCH 3/3] make docs --- docs/data-sources/rulesets.md | 2 +- docs/resources/ruleset.md | 7 ++++--- examples/resources/cloudflare_ruleset/resource.tf | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/data-sources/rulesets.md b/docs/data-sources/rulesets.md index 19612f2bcb..dc0a8e2276 100644 --- a/docs/data-sources/rulesets.md +++ b/docs/data-sources/rulesets.md @@ -189,9 +189,9 @@ Read-Only: Read-Only: - `check_presence` (List of String) +- `contains` (Map of Set of String) - `exclude_origin` (Boolean) - `include` (List of String) -- `contains` (Map of String to List) diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index d5766a454e..8ff160c4d2 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -301,9 +301,9 @@ resource "cloudflare_ruleset" "cache_settings_example" { check_presence = ["habc_t", "hdef_t"] exclude_origin = true contains = { - "accept" = ["image/web", "image/png"] - "accept-encoding = ["br", "zstd"] - "some-header" = ["some-value", "some-other-value"] + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] } } cookie { @@ -607,6 +607,7 @@ Optional: Optional: - `check_presence` (Set of String) List of headers to check for presence in the custom key. +- `contains` (Map of Set of String) Dictionary of headers mapping to lists of values to check for presence in the custom key. - `exclude_origin` (Boolean) Exclude the origin header from the custom key. - `include` (Set of String) List of headers to include in the custom key. diff --git a/examples/resources/cloudflare_ruleset/resource.tf b/examples/resources/cloudflare_ruleset/resource.tf index 7e30c6b559..e94b3b5bf1 100644 --- a/examples/resources/cloudflare_ruleset/resource.tf +++ b/examples/resources/cloudflare_ruleset/resource.tf @@ -276,9 +276,9 @@ resource "cloudflare_ruleset" "cache_settings_example" { check_presence = ["habc_t", "hdef_t"] exclude_origin = true contains = { - "accept" = ["image/web", "image/png"] - "accept-encoding = ["br", "zstd"] - "some-header" = ["some-value", "some-other-value"] + "accept" = ["image/web", "image/png"] + "accept-encoding" = ["br", "zstd"] + "some-header" = ["some-value", "some-other-value"] } } cookie {