From a0e96dc16156a70c99c864c073b9f61abc474e8f Mon Sep 17 00:00:00 2001 From: Mikey Sleevi Date: Sun, 10 Sep 2023 18:48:58 -0600 Subject: [PATCH 1/2] Add support for the use of Additional Cacheable Ports in Cache Rules --- .changelog/2754.txt | 3 + internal/framework/expanders/intset.go | 14 +++ internal/framework/flatteners/int64set.go | 19 ++++ internal/framework/service/rulesets/model.go | 101 +++++++++--------- .../framework/service/rulesets/resource.go | 12 +++ .../service/rulesets/resource_test.go | 2 + internal/framework/service/rulesets/schema.go | 5 + .../sdkv2provider/data_source_rulesets.go | 8 ++ 8 files changed, 114 insertions(+), 50 deletions(-) create mode 100644 .changelog/2754.txt create mode 100644 internal/framework/expanders/intset.go create mode 100644 internal/framework/flatteners/int64set.go diff --git a/.changelog/2754.txt b/.changelog/2754.txt new file mode 100644 index 0000000000..9443569a06 --- /dev/null +++ b/.changelog/2754.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/cloudflare_ruleset: Add support for the use of Additional Cacheable Ports option in the Rulesets API +``` diff --git a/internal/framework/expanders/intset.go b/internal/framework/expanders/intset.go new file mode 100644 index 0000000000..183557c8cb --- /dev/null +++ b/internal/framework/expanders/intset.go @@ -0,0 +1,14 @@ +package expanders + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Int64Set accepts a `types.Set` and returns a slice of int64. +func Int64Set(ctx context.Context, in types.Set) []int { + results := []int{} + _ = in.ElementsAs(ctx, &results, false) + return results +} diff --git a/internal/framework/flatteners/int64set.go b/internal/framework/flatteners/int64set.go new file mode 100644 index 0000000000..5baaf12218 --- /dev/null +++ b/internal/framework/flatteners/int64set.go @@ -0,0 +1,19 @@ +package flatteners + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +// Int64Set accepts a `[]attr.Value` and returns a `basetypes.SetValue`. The +// return type automatically handles `SetNull` for empty results and coercing +// all element values to a string if there are any elements. +// +// nolint: contextcheck +func Int64Set(in []attr.Value) basetypes.SetValue { + if len(in) == 0 { + return types.SetNull(types.Int64Type) + } + return types.SetValueMust(types.Int64Type, in) +} diff --git a/internal/framework/service/rulesets/model.go b/internal/framework/service/rulesets/model.go index a1453e72d0..fc591ec464 100644 --- a/internal/framework/service/rulesets/model.go +++ b/internal/framework/service/rulesets/model.go @@ -29,56 +29,57 @@ type RulesModel struct { } type ActionParametersModel struct { - Version types.String `tfsdk:"version"` - AutomaticHTTPSRewrites types.Bool `tfsdk:"automatic_https_rewrites"` - AutoMinify []*ActionParameterAutoMinifyModel `tfsdk:"autominify"` - BIC types.Bool `tfsdk:"bic"` - BrowserTTL []*ActionParameterBrowserTTLModel `tfsdk:"browser_ttl"` - Cache types.Bool `tfsdk:"cache"` - CacheKey []*ActionParameterCacheKeyModel `tfsdk:"cache_key"` - Content types.String `tfsdk:"content"` - ContentType types.String `tfsdk:"content_type"` - CookieFields types.Set `tfsdk:"cookie_fields"` - DisableApps types.Bool `tfsdk:"disable_apps"` - DisableRailgun types.Bool `tfsdk:"disable_railgun"` - DisableZaraz types.Bool `tfsdk:"disable_zaraz"` - EdgeTTL []*ActionParameterEdgeTTLModel `tfsdk:"edge_ttl"` - EmailObfuscation types.Bool `tfsdk:"email_obfuscation"` - FromList []*ActionParameterFromListModel `tfsdk:"from_list"` - FromValue []*ActionParameterFromValueModel `tfsdk:"from_value"` - Headers []*ActionParametersHeadersModel `tfsdk:"headers"` - HostHeader types.String `tfsdk:"host_header"` - HotlinkProtection types.Bool `tfsdk:"hotlink_protection"` - ID types.String `tfsdk:"id"` - Increment types.Int64 `tfsdk:"increment"` - MatchedData []*ActionParametersMatchedDataModel `tfsdk:"matched_data"` - Mirage types.Bool `tfsdk:"mirage"` - OpportunisticEncryption types.Bool `tfsdk:"opportunistic_encryption"` - Origin []*ActionParameterOriginModel `tfsdk:"origin"` - OriginCacheControl types.Bool `tfsdk:"origin_cache_control"` - OriginErrorPagePassthru types.Bool `tfsdk:"origin_error_page_passthru"` - Overrides []*ActionParameterOverridesModel `tfsdk:"overrides"` - Phases types.Set `tfsdk:"phases"` - Polish types.String `tfsdk:"polish"` - Products types.Set `tfsdk:"products"` - ReadTimeout types.Int64 `tfsdk:"read_timeout"` - RequestFields types.Set `tfsdk:"request_fields"` - RespectStrongEtags types.Bool `tfsdk:"respect_strong_etags"` - Response []*ActionParameterResponseModel `tfsdk:"response"` - ResponseFields types.Set `tfsdk:"response_fields"` - RocketLoader types.Bool `tfsdk:"rocket_loader"` - Rules map[string]types.String `tfsdk:"rules"` - Ruleset types.String `tfsdk:"ruleset"` - Rulesets types.Set `tfsdk:"rulesets"` - SecurityLevel types.String `tfsdk:"security_level"` - ServerSideExcludes types.Bool `tfsdk:"server_side_excludes"` - ServeStale []*ActionParameterServeStaleModel `tfsdk:"serve_stale"` - SNI []*ActionParameterSNIModel `tfsdk:"sni"` - SSL types.String `tfsdk:"ssl"` - StatusCode types.Int64 `tfsdk:"status_code"` - SXG types.Bool `tfsdk:"sxg"` - URI []*ActionParametersURIModel `tfsdk:"uri"` - Algorithms []*ActionParametersCompressionAlgorithmModel `tfsdk:"algorithms"` + Version types.String `tfsdk:"version"` + AdditionalCacheablePorts types.Set `tfsdk:"additional_cacheable_ports"` + AutomaticHTTPSRewrites types.Bool `tfsdk:"automatic_https_rewrites"` + AutoMinify []*ActionParameterAutoMinifyModel `tfsdk:"autominify"` + BIC types.Bool `tfsdk:"bic"` + BrowserTTL []*ActionParameterBrowserTTLModel `tfsdk:"browser_ttl"` + Cache types.Bool `tfsdk:"cache"` + CacheKey []*ActionParameterCacheKeyModel `tfsdk:"cache_key"` + Content types.String `tfsdk:"content"` + ContentType types.String `tfsdk:"content_type"` + CookieFields types.Set `tfsdk:"cookie_fields"` + DisableApps types.Bool `tfsdk:"disable_apps"` + DisableRailgun types.Bool `tfsdk:"disable_railgun"` + DisableZaraz types.Bool `tfsdk:"disable_zaraz"` + EdgeTTL []*ActionParameterEdgeTTLModel `tfsdk:"edge_ttl"` + EmailObfuscation types.Bool `tfsdk:"email_obfuscation"` + FromList []*ActionParameterFromListModel `tfsdk:"from_list"` + FromValue []*ActionParameterFromValueModel `tfsdk:"from_value"` + Headers []*ActionParametersHeadersModel `tfsdk:"headers"` + HostHeader types.String `tfsdk:"host_header"` + HotlinkProtection types.Bool `tfsdk:"hotlink_protection"` + ID types.String `tfsdk:"id"` + Increment types.Int64 `tfsdk:"increment"` + MatchedData []*ActionParametersMatchedDataModel `tfsdk:"matched_data"` + Mirage types.Bool `tfsdk:"mirage"` + OpportunisticEncryption types.Bool `tfsdk:"opportunistic_encryption"` + Origin []*ActionParameterOriginModel `tfsdk:"origin"` + OriginCacheControl types.Bool `tfsdk:"origin_cache_control"` + OriginErrorPagePassthru types.Bool `tfsdk:"origin_error_page_passthru"` + Overrides []*ActionParameterOverridesModel `tfsdk:"overrides"` + Phases types.Set `tfsdk:"phases"` + Polish types.String `tfsdk:"polish"` + Products types.Set `tfsdk:"products"` + ReadTimeout types.Int64 `tfsdk:"read_timeout"` + RequestFields types.Set `tfsdk:"request_fields"` + RespectStrongEtags types.Bool `tfsdk:"respect_strong_etags"` + Response []*ActionParameterResponseModel `tfsdk:"response"` + ResponseFields types.Set `tfsdk:"response_fields"` + RocketLoader types.Bool `tfsdk:"rocket_loader"` + Rules map[string]types.String `tfsdk:"rules"` + Ruleset types.String `tfsdk:"ruleset"` + Rulesets types.Set `tfsdk:"rulesets"` + SecurityLevel types.String `tfsdk:"security_level"` + ServerSideExcludes types.Bool `tfsdk:"server_side_excludes"` + ServeStale []*ActionParameterServeStaleModel `tfsdk:"serve_stale"` + SNI []*ActionParameterSNIModel `tfsdk:"sni"` + SSL types.String `tfsdk:"ssl"` + StatusCode types.Int64 `tfsdk:"status_code"` + SXG types.Bool `tfsdk:"sxg"` + URI []*ActionParametersURIModel `tfsdk:"uri"` + Algorithms []*ActionParametersCompressionAlgorithmModel `tfsdk:"algorithms"` } type ActionParameterOverridesModel struct { diff --git a/internal/framework/service/rulesets/resource.go b/internal/framework/service/rulesets/resource.go index 05057a710e..f7c1b6f92a 100644 --- a/internal/framework/service/rulesets/resource.go +++ b/internal/framework/service/rulesets/resource.go @@ -359,6 +359,14 @@ func toRulesetResourceModel(ctx context.Context, zoneID, accountID basetypes.Str Version: flatteners.String(cloudflare.String(ruleResponse.ActionParameters.Version)), }) + if !reflect.ValueOf(ruleResponse.ActionParameters.AdditionalCacheablePorts).IsNil() { + var ports []attr.Value + for _, s := range ruleResponse.ActionParameters.AdditionalCacheablePorts { + ports = append(ports, types.Int64Value((int64(s)))) + } + rule.ActionParameters[0].AdditionalCacheablePorts = flatteners.Int64Set(ports) + } + if !reflect.ValueOf(ruleResponse.ActionParameters.Polish).IsNil() { rule.ActionParameters[0].Polish = flatteners.String(ruleResponse.ActionParameters.Polish.String()) } @@ -850,6 +858,10 @@ func (r *RulesModel) toRulesetRule(ctx context.Context) cloudflare.RulesetRule { rr.ActionParameters.StatusCode = uint16(ap.StatusCode.ValueInt64()) } + if !ap.AdditionalCacheablePorts.IsNull() { + rr.ActionParameters.AdditionalCacheablePorts = expanders.Int64Set(ctx, ap.AdditionalCacheablePorts) + } + if !ap.AutomaticHTTPSRewrites.IsNull() { rr.ActionParameters.AutomaticHTTPSRewrites = cloudflare.BoolPtr(ap.AutomaticHTTPSRewrites.ValueBool()) } diff --git a/internal/framework/service/rulesets/resource_test.go b/internal/framework/service/rulesets/resource_test.go index 8ccbe91cb7..a8f697d233 100644 --- a/internal/framework/service/rulesets/resource_test.go +++ b/internal/framework/service/rulesets/resource_test.go @@ -1805,6 +1805,7 @@ func TestAccCloudflareRuleset_CacheSettingsAllEnabled(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "rules.0.action", "set_cache_settings"), resource.TestCheckResourceAttr(resourceName, "rules.0.description", rnd+" set cache settings rule"), + resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.additional_cacheable_ports.0", "8443"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.edge_ttl.0.mode", "override_origin"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.edge_ttl.0.default", "60"), resource.TestCheckResourceAttr(resourceName, "rules.0.action_parameters.0.edge_ttl.0.status_code_ttl.#", "2"), @@ -3917,6 +3918,7 @@ func testAccCloudflareRulesetCacheSettingsAllEnabled(rnd, accountID, zoneID stri rules { action = "set_cache_settings" action_parameters { + additional_cacheable_ports = [8443] edge_ttl { mode = "override_origin" default = 60 diff --git a/internal/framework/service/rulesets/schema.go b/internal/framework/service/rulesets/schema.go index b7c7ea58c4..c9cb119230 100644 --- a/internal/framework/service/rulesets/schema.go +++ b/internal/framework/service/rulesets/schema.go @@ -154,6 +154,11 @@ func (r *RulesetResource) Schema(ctx context.Context, req resource.SchemaRequest MarkdownDescription: "List of parameters that configure the behavior of the ruleset rule action.", NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ + "additional_cacheable_ports": schema.SetAttribute{ + ElementType: types.Int64Type, + Optional: true, + MarkdownDescription: "Specifies uncommon ports to allow cacheable assets to be served from.", + }, "automatic_https_rewrites": schema.BoolAttribute{ Optional: true, MarkdownDescription: "Turn on or off Cloudflare Automatic HTTPS rewrites.", diff --git a/internal/sdkv2provider/data_source_rulesets.go b/internal/sdkv2provider/data_source_rulesets.go index 7cb670b678..109948de0e 100644 --- a/internal/sdkv2provider/data_source_rulesets.go +++ b/internal/sdkv2provider/data_source_rulesets.go @@ -473,6 +473,14 @@ func resourceCloudflareRulesetSchema() map[string]*schema.Schema { Optional: true, Description: "Whether to cache if expression matches.", }, + "additional_cacheable_ports": { + Type: schema.TypeSet, + Optional: true, + Description: "Allows for the ability to support caching on non-standard ports.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, "automatic_https_rewrites": { Type: schema.TypeBool, Optional: true, From 9432a38ce02a25e112e0696b689f8717e117d324 Mon Sep 17 00:00:00 2001 From: Chenxi Zhang Date: Mon, 16 Oct 2023 17:21:48 -0700 Subject: [PATCH 2/2] Fix additional_cacheable_ports empty case --- .changelog/{2754.txt => 2854.txt} | 0 internal/framework/flatteners/int64set.go | 19 ------------------- internal/framework/flatteners/set.go | 12 ++++++++++++ .../framework/service/rulesets/resource.go | 14 ++++++-------- 4 files changed, 18 insertions(+), 27 deletions(-) rename .changelog/{2754.txt => 2854.txt} (100%) delete mode 100644 internal/framework/flatteners/int64set.go diff --git a/.changelog/2754.txt b/.changelog/2854.txt similarity index 100% rename from .changelog/2754.txt rename to .changelog/2854.txt diff --git a/internal/framework/flatteners/int64set.go b/internal/framework/flatteners/int64set.go deleted file mode 100644 index 5baaf12218..0000000000 --- a/internal/framework/flatteners/int64set.go +++ /dev/null @@ -1,19 +0,0 @@ -package flatteners - -import ( - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" -) - -// Int64Set accepts a `[]attr.Value` and returns a `basetypes.SetValue`. The -// return type automatically handles `SetNull` for empty results and coercing -// all element values to a string if there are any elements. -// -// nolint: contextcheck -func Int64Set(in []attr.Value) basetypes.SetValue { - if len(in) == 0 { - return types.SetNull(types.Int64Type) - } - return types.SetValueMust(types.Int64Type, in) -} diff --git a/internal/framework/flatteners/set.go b/internal/framework/flatteners/set.go index e5d4381a30..a19b484c21 100644 --- a/internal/framework/flatteners/set.go +++ b/internal/framework/flatteners/set.go @@ -17,3 +17,15 @@ func StringSet(in []attr.Value) basetypes.SetValue { } return types.SetValueMust(types.StringType, in) } + +// Int64Set accepts a `[]attr.Value` and returns a `basetypes.SetValue`. The +// return type automatically handles `SetNull` for empty results and coercing +// all element values to a string if there are any elements. +// +// nolint: contextcheck +func Int64Set(in []attr.Value) basetypes.SetValue { + if len(in) == 0 { + return types.SetNull(types.Int64Type) + } + return types.SetValueMust(types.Int64Type, in) +} diff --git a/internal/framework/service/rulesets/resource.go b/internal/framework/service/rulesets/resource.go index f7c1b6f92a..32b2535eb4 100644 --- a/internal/framework/service/rulesets/resource.go +++ b/internal/framework/service/rulesets/resource.go @@ -359,14 +359,6 @@ func toRulesetResourceModel(ctx context.Context, zoneID, accountID basetypes.Str Version: flatteners.String(cloudflare.String(ruleResponse.ActionParameters.Version)), }) - if !reflect.ValueOf(ruleResponse.ActionParameters.AdditionalCacheablePorts).IsNil() { - var ports []attr.Value - for _, s := range ruleResponse.ActionParameters.AdditionalCacheablePorts { - ports = append(ports, types.Int64Value((int64(s)))) - } - rule.ActionParameters[0].AdditionalCacheablePorts = flatteners.Int64Set(ports) - } - if !reflect.ValueOf(ruleResponse.ActionParameters.Polish).IsNil() { rule.ActionParameters[0].Polish = flatteners.String(ruleResponse.ActionParameters.Polish.String()) } @@ -379,6 +371,12 @@ func toRulesetResourceModel(ctx context.Context, zoneID, accountID basetypes.Str rule.ActionParameters[0].SSL = flatteners.String(ruleResponse.ActionParameters.SSL.String()) } + var ports []attr.Value + for _, s := range ruleResponse.ActionParameters.AdditionalCacheablePorts { + ports = append(ports, types.Int64Value((int64(s)))) + } + rule.ActionParameters[0].AdditionalCacheablePorts = flatteners.Int64Set(ports) + var phases []attr.Value for _, s := range ruleResponse.ActionParameters.Phases { phases = append(phases, types.StringValue(s))