cdn add geofence feature (#1020)
* add geofencing attribute to "stackit_cdn_distribution"
This commit is contained in:
parent
87bc7415fc
commit
f0433984f4
9 changed files with 324 additions and 23 deletions
|
|
@ -58,6 +58,7 @@ Read-Only:
|
||||||
|
|
||||||
Read-Only:
|
Read-Only:
|
||||||
|
|
||||||
|
- `geofencing` (Map of List of String) A map of URLs to a list of countries where content is allowed.
|
||||||
- `origin_request_headers` (Map of String) The configured origin request headers for the backend
|
- `origin_request_headers` (Map of String) The configured origin request headers for the backend
|
||||||
- `origin_url` (String) The configured backend type for the distribution
|
- `origin_url` (String) The configured backend type for the distribution
|
||||||
- `type` (String) The configured backend type. Supported values are: `http`.
|
- `type` (String) The configured backend type. Supported values are: `http`.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ resource "stackit_cdn_distribution" "example_distribution" {
|
||||||
backend = {
|
backend = {
|
||||||
type = "http"
|
type = "http"
|
||||||
origin_url = "https://mybackend.onstackit.cloud"
|
origin_url = "https://mybackend.onstackit.cloud"
|
||||||
|
geofencing = {
|
||||||
|
"https://mybackend.onstackit.cloud" = ["DE"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
regions = ["EU", "US", "ASIA", "AF", "SA"]
|
regions = ["EU", "US", "ASIA", "AF", "SA"]
|
||||||
blocked_countries = ["DE", "AT", "CH"]
|
blocked_countries = ["DE", "AT", "CH"]
|
||||||
|
|
@ -80,6 +83,7 @@ Required:
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
|
|
||||||
|
- `geofencing` (Map of List of String) A map of URLs to a list of countries where content is allowed.
|
||||||
- `origin_request_headers` (Map of String) The configured origin request headers for the backend
|
- `origin_request_headers` (Map of String) The configured origin request headers for the backend
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ resource "stackit_cdn_distribution" "example_distribution" {
|
||||||
backend = {
|
backend = {
|
||||||
type = "http"
|
type = "http"
|
||||||
origin_url = "https://mybackend.onstackit.cloud"
|
origin_url = "https://mybackend.onstackit.cloud"
|
||||||
|
geofencing = {
|
||||||
|
"https://mybackend.onstackit.cloud" = ["DE"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
regions = ["EU", "US", "ASIA", "AF", "SA"]
|
regions = ["EU", "US", "ASIA", "AF", "SA"]
|
||||||
blocked_countries = ["DE", "AT", "CH"]
|
blocked_countries = ["DE", "AT", "CH"]
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,13 @@ var instanceResource = map[string]string{
|
||||||
"dns_name": fmt.Sprintf("tf-acc-%s.stackit.gg", strings.Split(uuid.NewString(), "-")[0]),
|
"dns_name": fmt.Sprintf("tf-acc-%s.stackit.gg", strings.Split(uuid.NewString(), "-")[0]),
|
||||||
}
|
}
|
||||||
|
|
||||||
func configResources(regions string) string {
|
func configResources(regions string, geofencingCountries []string) string {
|
||||||
|
var quotedCountries []string
|
||||||
|
for _, country := range geofencingCountries {
|
||||||
|
quotedCountries = append(quotedCountries, fmt.Sprintf(`%q`, country))
|
||||||
|
}
|
||||||
|
|
||||||
|
geofencingList := strings.Join(quotedCountries, ",")
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
|
@ -45,6 +51,9 @@ func configResources(regions string) string {
|
||||||
backend = {
|
backend = {
|
||||||
type = "http"
|
type = "http"
|
||||||
origin_url = "%s"
|
origin_url = "%s"
|
||||||
|
geofencing = {
|
||||||
|
"%s" = [%s]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
regions = [%s]
|
regions = [%s]
|
||||||
blocked_countries = [%s]
|
blocked_countries = [%s]
|
||||||
|
|
@ -70,12 +79,12 @@ func configResources(regions string) string {
|
||||||
type = "CNAME"
|
type = "CNAME"
|
||||||
records = ["${stackit_cdn_distribution.distribution.domains[0].name}."]
|
records = ["${stackit_cdn_distribution.distribution.domains[0].name}."]
|
||||||
}
|
}
|
||||||
`, testutil.CdnProviderConfig(), testutil.ProjectId, instanceResource["config_backend_origin_url"],
|
`, testutil.CdnProviderConfig(), testutil.ProjectId, instanceResource["config_backend_origin_url"], instanceResource["config_backend_origin_url"], geofencingList,
|
||||||
regions, instanceResource["blocked_countries"], testutil.ProjectId, instanceResource["dns_name"],
|
regions, instanceResource["blocked_countries"], testutil.ProjectId, instanceResource["dns_name"],
|
||||||
testutil.ProjectId, instanceResource["custom_domain_prefix"])
|
testutil.ProjectId, instanceResource["custom_domain_prefix"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func configCustomDomainResources(regions, cert, key string) string {
|
func configCustomDomainResources(regions, cert, key string, geofencingCountries []string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
|
@ -88,10 +97,10 @@ func configCustomDomainResources(regions, cert, key string) string {
|
||||||
private_key = %q
|
private_key = %q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, configResources(regions), cert, key)
|
`, configResources(regions, geofencingCountries), cert, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configDatasources(regions, cert, key string) string {
|
func configDatasources(regions, cert, key string, geofencingCountries []string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
|
@ -106,7 +115,7 @@ func configDatasources(regions, cert, key string) string {
|
||||||
name = stackit_cdn_custom_domain.custom_domain.name
|
name = stackit_cdn_custom_domain.custom_domain.name
|
||||||
|
|
||||||
}
|
}
|
||||||
`, configCustomDomainResources(regions, cert, key))
|
`, configCustomDomainResources(regions, cert, key, geofencingCountries))
|
||||||
}
|
}
|
||||||
func makeCertAndKey(t *testing.T, organization string) (cert, key []byte) {
|
func makeCertAndKey(t *testing.T, organization string) (cert, key []byte) {
|
||||||
privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 2048)
|
privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 2048)
|
||||||
|
|
@ -149,6 +158,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
fullDomainName := fmt.Sprintf("%s.%s", instanceResource["custom_domain_prefix"], instanceResource["dns_name"])
|
fullDomainName := fmt.Sprintf("%s.%s", instanceResource["custom_domain_prefix"], instanceResource["dns_name"])
|
||||||
organization := fmt.Sprintf("organization-%s", uuid.NewString())
|
organization := fmt.Sprintf("organization-%s", uuid.NewString())
|
||||||
cert, key := makeCertAndKey(t, organization)
|
cert, key := makeCertAndKey(t, organization)
|
||||||
|
geofencing := []string{"DE", "ES"}
|
||||||
|
|
||||||
organization_updated := fmt.Sprintf("organization-updated-%s", uuid.NewString())
|
organization_updated := fmt.Sprintf("organization-updated-%s", uuid.NewString())
|
||||||
cert_updated, key_updated := makeCertAndKey(t, organization_updated)
|
cert_updated, key_updated := makeCertAndKey(t, organization_updated)
|
||||||
|
|
@ -158,7 +168,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
// Distribution Create
|
// Distribution Create
|
||||||
{
|
{
|
||||||
Config: configResources(instanceResource["config_regions"]),
|
Config: configResources(instanceResource["config_regions"], geofencing),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
|
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
|
||||||
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "created_at"),
|
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "created_at"),
|
||||||
|
|
@ -173,6 +183,16 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.#", "2"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.#", "2"),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.0", "CU"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.0", "CU"),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.1", "AQ"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.1", "AQ"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"stackit_cdn_distribution.distribution",
|
||||||
|
fmt.Sprintf("config.backend.geofencing.%s.0", instanceResource["config_backend_origin_url"]),
|
||||||
|
"DE",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"stackit_cdn_distribution.distribution",
|
||||||
|
fmt.Sprintf("config.backend.geofencing.%s.1", instanceResource["config_backend_origin_url"]),
|
||||||
|
"ES",
|
||||||
|
),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.optimizer.enabled", "true"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.optimizer.enabled", "true"),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "project_id", testutil.ProjectId),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "project_id", testutil.ProjectId),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "status", "ACTIVE"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "status", "ACTIVE"),
|
||||||
|
|
@ -180,7 +200,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Wait step, that confirms the CNAME record has "propagated"
|
// Wait step, that confirms the CNAME record has "propagated"
|
||||||
{
|
{
|
||||||
Config: configResources(instanceResource["config_regions"]),
|
Config: configResources(instanceResource["config_regions"], geofencing),
|
||||||
Check: func(_ *terraform.State) error {
|
Check: func(_ *terraform.State) error {
|
||||||
_, err := blockUntilDomainResolves(fullDomainName)
|
_, err := blockUntilDomainResolves(fullDomainName)
|
||||||
return err
|
return err
|
||||||
|
|
@ -188,7 +208,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Custom Domain Create
|
// Custom Domain Create
|
||||||
{
|
{
|
||||||
Config: configCustomDomainResources(instanceResource["config_regions"], string(cert), string(key)),
|
Config: configCustomDomainResources(instanceResource["config_regions"], string(cert), string(key), geofencing),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "status", "ACTIVE"),
|
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "status", "ACTIVE"),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "name", fullDomainName),
|
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "name", fullDomainName),
|
||||||
|
|
@ -242,7 +262,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Data Source
|
// Data Source
|
||||||
{
|
{
|
||||||
Config: configDatasources(instanceResource["config_regions"], string(cert), string(key)),
|
Config: configDatasources(instanceResource["config_regions"], string(cert), string(key), geofencing),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttrSet("data.stackit_cdn_distribution.distribution", "distribution_id"),
|
resource.TestCheckResourceAttrSet("data.stackit_cdn_distribution.distribution", "distribution_id"),
|
||||||
resource.TestCheckResourceAttrSet("data.stackit_cdn_distribution.distribution", "created_at"),
|
resource.TestCheckResourceAttrSet("data.stackit_cdn_distribution.distribution", "created_at"),
|
||||||
|
|
@ -255,6 +275,16 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.0.type", "managed"),
|
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.0.type", "managed"),
|
||||||
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.1.type", "custom"),
|
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.1.type", "custom"),
|
||||||
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.#", "2"),
|
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.#", "2"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.stackit_cdn_distribution.distribution",
|
||||||
|
fmt.Sprintf("config.backend.geofencing.%s.0", instanceResource["config_backend_origin_url"]),
|
||||||
|
"DE",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"data.stackit_cdn_distribution.distribution",
|
||||||
|
fmt.Sprintf("config.backend.geofencing.%s.1", instanceResource["config_backend_origin_url"]),
|
||||||
|
"ES",
|
||||||
|
),
|
||||||
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.0", "EU"),
|
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.0", "EU"),
|
||||||
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.1", "US"),
|
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "config.regions.1", "US"),
|
||||||
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.#", "2"),
|
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "config.blocked_countries.#", "2"),
|
||||||
|
|
@ -271,7 +301,7 @@ func TestAccCDNDistributionResource(t *testing.T) {
|
||||||
},
|
},
|
||||||
// Update
|
// Update
|
||||||
{
|
{
|
||||||
Config: configCustomDomainResources(instanceResource["config_regions_updated"], string(cert_updated), string(key_updated)),
|
Config: configCustomDomainResources(instanceResource["config_regions_updated"], string(cert_updated), string(key_updated), geofencing),
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
|
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
|
||||||
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "created_at"),
|
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "created_at"),
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,13 @@ func (r *distributionDataSource) Schema(_ context.Context, _ datasource.SchemaRe
|
||||||
Description: schemaDescriptions["config_backend_origin_request_headers"],
|
Description: schemaDescriptions["config_backend_origin_request_headers"],
|
||||||
ElementType: types.StringType,
|
ElementType: types.StringType,
|
||||||
},
|
},
|
||||||
|
"geofencing": schema.MapAttribute{
|
||||||
|
Description: "A map of URLs to a list of countries where content is allowed.",
|
||||||
|
Computed: true,
|
||||||
|
ElementType: types.ListType{
|
||||||
|
ElemType: types.StringType,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"regions": schema.ListAttribute{
|
"regions": schema.ListAttribute{
|
||||||
|
|
@ -192,7 +199,7 @@ func (r *distributionDataSource) Read(ctx context.Context, req datasource.ReadRe
|
||||||
resp.State.RemoveResource(ctx)
|
resp.State.RemoveResource(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = mapFields(distributionResp.Distribution, &model)
|
err = mapFields(ctx, distributionResp.Distribution, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN distribution", fmt.Sprintf("Error processing API response: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN distribution", fmt.Sprintf("Error processing API response: %v", err))
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
|
|
||||||
cdnUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/cdn/utils"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
|
"github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
|
|
@ -28,8 +26,10 @@ import (
|
||||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/services/cdn"
|
"github.com/stackitcloud/stackit-sdk-go/services/cdn"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/services/cdn/wait"
|
"github.com/stackitcloud/stackit-sdk-go/services/cdn/wait"
|
||||||
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
|
||||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
|
||||||
|
cdnUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/cdn/utils"
|
||||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
|
||||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
|
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
|
||||||
)
|
)
|
||||||
|
|
@ -88,9 +88,10 @@ type optimizerConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type backend struct {
|
type backend struct {
|
||||||
Type string `tfsdk:"type"` // The type of the backend. Currently, only "http" backend is supported
|
Type string `tfsdk:"type"` // The type of the backend. Currently, only "http" backend is supported
|
||||||
OriginURL string `tfsdk:"origin_url"` // The origin URL of the backend
|
OriginURL string `tfsdk:"origin_url"` // The origin URL of the backend
|
||||||
OriginRequestHeaders *map[string]string `tfsdk:"origin_request_headers"` // Request headers that should be added by the CDN distribution to incoming requests
|
OriginRequestHeaders *map[string]string `tfsdk:"origin_request_headers"` // Request headers that should be added by the CDN distribution to incoming requests
|
||||||
|
Geofencing *map[string][]*string `tfsdk:"geofencing"` // The geofencing is an object mapping multiple alternative origins to country codes.
|
||||||
}
|
}
|
||||||
|
|
||||||
var configTypes = map[string]attr.Type{
|
var configTypes = map[string]attr.Type{
|
||||||
|
|
@ -106,10 +107,15 @@ var optimizerTypes = map[string]attr.Type{
|
||||||
"enabled": types.BoolType,
|
"enabled": types.BoolType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var geofencingTypes = types.MapType{ElemType: types.ListType{
|
||||||
|
ElemType: types.StringType,
|
||||||
|
}}
|
||||||
|
|
||||||
var backendTypes = map[string]attr.Type{
|
var backendTypes = map[string]attr.Type{
|
||||||
"type": types.StringType,
|
"type": types.StringType,
|
||||||
"origin_url": types.StringType,
|
"origin_url": types.StringType,
|
||||||
"origin_request_headers": types.MapType{ElemType: types.StringType},
|
"origin_request_headers": types.MapType{ElemType: types.StringType},
|
||||||
|
"geofencing": geofencingTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
var domainTypes = map[string]attr.Type{
|
var domainTypes = map[string]attr.Type{
|
||||||
|
|
@ -256,6 +262,16 @@ func (r *distributionResource) Schema(_ context.Context, _ resource.SchemaReques
|
||||||
Description: schemaDescriptions["config_backend_origin_request_headers"],
|
Description: schemaDescriptions["config_backend_origin_request_headers"],
|
||||||
ElementType: types.StringType,
|
ElementType: types.StringType,
|
||||||
},
|
},
|
||||||
|
"geofencing": schema.MapAttribute{
|
||||||
|
Description: "A map of URLs to a list of countries where content is allowed.",
|
||||||
|
Optional: true,
|
||||||
|
ElementType: types.ListType{
|
||||||
|
ElemType: types.StringType,
|
||||||
|
},
|
||||||
|
Validators: []validator.Map{
|
||||||
|
mapvalidator.SizeAtLeast(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"regions": schema.ListAttribute{
|
"regions": schema.ListAttribute{
|
||||||
|
|
@ -274,6 +290,43 @@ func (r *distributionResource) Schema(_ context.Context, _ resource.SchemaReques
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *distributionResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
|
||||||
|
var model Model
|
||||||
|
resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utils.IsUndefined(model.Config) {
|
||||||
|
var config distributionConfig
|
||||||
|
if !model.Config.IsNull() {
|
||||||
|
diags := model.Config.As(ctx, &config, basetypes.ObjectAsOptions{})
|
||||||
|
if diags.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if geofencing := config.Backend.Geofencing; geofencing != nil {
|
||||||
|
for url, region := range *geofencing {
|
||||||
|
if region == nil {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Invalid geofencing config", fmt.Sprintf("The list of countries for URL %q must not be null.", url))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(region) == 0 {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Invalid geofencing config", fmt.Sprintf("The list of countries for URL %q must not be empty.", url))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, countryPtr := range region {
|
||||||
|
if countryPtr == nil {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Invalid geofencing config", fmt.Sprintf("Found a null value in the country list for URL %q at index %d.", url, i))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *distributionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform
|
func (r *distributionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform
|
||||||
var model Model
|
var model Model
|
||||||
diags := req.Plan.Get(ctx, &model)
|
diags := req.Plan.Get(ctx, &model)
|
||||||
|
|
@ -301,7 +354,7 @@ func (r *distributionResource) Create(ctx context.Context, req resource.CreateRe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mapFields(waitResp.Distribution, &model)
|
err = mapFields(ctx, waitResp.Distribution, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating CDN distribution", fmt.Sprintf("Processing API payload: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating CDN distribution", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -341,7 +394,7 @@ func (r *distributionResource) Read(ctx context.Context, req resource.ReadReques
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN distribution", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN distribution", fmt.Sprintf("Calling API: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = mapFields(cdnResp.Distribution, &model)
|
err = mapFields(ctx, cdnResp.Distribution, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN ditribution", fmt.Sprintf("Processing API payload: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading CDN ditribution", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -408,12 +461,30 @@ func (r *distributionResource) Update(ctx context.Context, req resource.UpdateRe
|
||||||
blockedCountries = &tempBlockedCountries
|
blockedCountries = &tempBlockedCountries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geofencingPatch := map[string][]string{}
|
||||||
|
if configModel.Backend.Geofencing != nil {
|
||||||
|
gf := make(map[string][]string)
|
||||||
|
for url, countries := range *configModel.Backend.Geofencing {
|
||||||
|
countryStrings := make([]string, len(countries))
|
||||||
|
for i, countryPtr := range countries {
|
||||||
|
if countryPtr == nil {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Update CDN distribution", fmt.Sprintf("Geofencing url %q has a null value", url))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
countryStrings[i] = *countryPtr
|
||||||
|
}
|
||||||
|
gf[url] = countryStrings
|
||||||
|
}
|
||||||
|
geofencingPatch = gf
|
||||||
|
}
|
||||||
|
|
||||||
configPatch := &cdn.ConfigPatch{
|
configPatch := &cdn.ConfigPatch{
|
||||||
Backend: &cdn.ConfigPatchBackend{
|
Backend: &cdn.ConfigPatchBackend{
|
||||||
HttpBackendPatch: &cdn.HttpBackendPatch{
|
HttpBackendPatch: &cdn.HttpBackendPatch{
|
||||||
OriginRequestHeaders: configModel.Backend.OriginRequestHeaders,
|
OriginRequestHeaders: configModel.Backend.OriginRequestHeaders,
|
||||||
OriginUrl: &configModel.Backend.OriginURL,
|
OriginUrl: &configModel.Backend.OriginURL,
|
||||||
Type: &configModel.Backend.Type,
|
Type: &configModel.Backend.Type,
|
||||||
|
Geofencing: &geofencingPatch, // Use the converted variable
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Regions: ®ions,
|
Regions: ®ions,
|
||||||
|
|
@ -451,7 +522,7 @@ func (r *distributionResource) Update(ctx context.Context, req resource.UpdateRe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mapFields(waitResp.Distribution, &model)
|
err = mapFields(ctx, waitResp.Distribution, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Update CDN distribution", fmt.Sprintf("Processing API payload: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Update CDN distribution", fmt.Sprintf("Processing API payload: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -500,7 +571,7 @@ func (r *distributionResource) ImportState(ctx context.Context, req resource.Imp
|
||||||
tflog.Info(ctx, "CDN distribution state imported")
|
tflog.Info(ctx, "CDN distribution state imported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapFields(distribution *cdn.Distribution, model *Model) error {
|
func mapFields(ctx context.Context, distribution *cdn.Distribution, model *Model) error {
|
||||||
if distribution == nil {
|
if distribution == nil {
|
||||||
return fmt.Errorf("response input is nil")
|
return fmt.Errorf("response input is nil")
|
||||||
}
|
}
|
||||||
|
|
@ -584,11 +655,58 @@ func mapFields(distribution *cdn.Distribution, model *Model) error {
|
||||||
return core.DiagsToError(diags)
|
return core.DiagsToError(diags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// geofencing
|
||||||
|
var oldConfig distributionConfig
|
||||||
|
oldGeofencingMap := make(map[string][]*string)
|
||||||
|
if !model.Config.IsNull() {
|
||||||
|
diags = model.Config.As(ctx, &oldConfig, basetypes.ObjectAsOptions{})
|
||||||
|
if diags.HasError() {
|
||||||
|
return core.DiagsToError(diags)
|
||||||
|
}
|
||||||
|
if oldConfig.Backend.Geofencing != nil {
|
||||||
|
oldGeofencingMap = *oldConfig.Backend.Geofencing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reconciledGeofencingData := make(map[string][]string)
|
||||||
|
if geofencingAPI := distribution.Config.Backend.HttpBackend.Geofencing; geofencingAPI != nil && len(*geofencingAPI) > 0 {
|
||||||
|
newGeofencingMap := *geofencingAPI
|
||||||
|
for url, newCountries := range newGeofencingMap {
|
||||||
|
oldCountriesPtrs := oldGeofencingMap[url]
|
||||||
|
|
||||||
|
oldCountries := utils.ConvertPointerSliceToStringSlice(oldCountriesPtrs)
|
||||||
|
|
||||||
|
reconciledCountries := utils.ReconcileStringSlices(oldCountries, newCountries)
|
||||||
|
reconciledGeofencingData[url] = reconciledCountries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geofencingVal := types.MapNull(geofencingTypes.ElemType)
|
||||||
|
if len(reconciledGeofencingData) > 0 {
|
||||||
|
geofencingMapElems := make(map[string]attr.Value)
|
||||||
|
for url, countries := range reconciledGeofencingData {
|
||||||
|
listVal, diags := types.ListValueFrom(ctx, types.StringType, countries)
|
||||||
|
if diags.HasError() {
|
||||||
|
return core.DiagsToError(diags)
|
||||||
|
}
|
||||||
|
geofencingMapElems[url] = listVal
|
||||||
|
}
|
||||||
|
|
||||||
|
var mappedGeofencing basetypes.MapValue
|
||||||
|
mappedGeofencing, diags = types.MapValue(geofencingTypes.ElemType, geofencingMapElems)
|
||||||
|
if diags.HasError() {
|
||||||
|
return core.DiagsToError(diags)
|
||||||
|
}
|
||||||
|
geofencingVal = mappedGeofencing
|
||||||
|
}
|
||||||
|
|
||||||
// note that httpbackend is hardcoded here as long as it is the only available backend
|
// note that httpbackend is hardcoded here as long as it is the only available backend
|
||||||
backend, diags := types.ObjectValue(backendTypes, map[string]attr.Value{
|
backend, diags := types.ObjectValue(backendTypes, map[string]attr.Value{
|
||||||
"type": types.StringValue(*distribution.Config.Backend.HttpBackend.Type),
|
"type": types.StringValue(*distribution.Config.Backend.HttpBackend.Type),
|
||||||
"origin_url": types.StringValue(*distribution.Config.Backend.HttpBackend.OriginUrl),
|
"origin_url": types.StringValue(*distribution.Config.Backend.HttpBackend.OriginUrl),
|
||||||
"origin_request_headers": originRequestHeaders,
|
"origin_request_headers": originRequestHeaders,
|
||||||
|
"geofencing": geofencingVal,
|
||||||
})
|
})
|
||||||
if diags.HasError() {
|
if diags.HasError() {
|
||||||
return core.DiagsToError(diags)
|
return core.DiagsToError(diags)
|
||||||
|
|
@ -678,6 +796,7 @@ func toCreatePayload(ctx context.Context, model *Model) (*cdn.CreateDistribution
|
||||||
Regions: cfg.Regions,
|
Regions: cfg.Regions,
|
||||||
BlockedCountries: cfg.BlockedCountries,
|
BlockedCountries: cfg.BlockedCountries,
|
||||||
OriginRequestHeaders: cfg.Backend.HttpBackend.OriginRequestHeaders,
|
OriginRequestHeaders: cfg.Backend.HttpBackend.OriginRequestHeaders,
|
||||||
|
Geofencing: cfg.Backend.HttpBackend.Geofencing,
|
||||||
Optimizer: optimizer,
|
Optimizer: optimizer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -722,6 +841,25 @@ func convertConfig(ctx context.Context, model *Model) (*cdn.Config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// geofencing
|
||||||
|
geofencing := map[string][]string{}
|
||||||
|
if configModel.Backend.Geofencing != nil {
|
||||||
|
for endpoint, countryCodes := range *configModel.Backend.Geofencing {
|
||||||
|
geofencingCountry := make([]string, len(countryCodes))
|
||||||
|
for i, countryCodePtr := range countryCodes {
|
||||||
|
if countryCodePtr == nil {
|
||||||
|
return nil, fmt.Errorf("geofencing url %q has a null value", endpoint)
|
||||||
|
}
|
||||||
|
validatedCountry, err := validateCountryCode(*countryCodePtr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
geofencingCountry[i] = validatedCountry
|
||||||
|
}
|
||||||
|
geofencing[endpoint] = geofencingCountry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// originRequestHeaders
|
// originRequestHeaders
|
||||||
originRequestHeaders := map[string]string{}
|
originRequestHeaders := map[string]string{}
|
||||||
if configModel.Backend.OriginRequestHeaders != nil {
|
if configModel.Backend.OriginRequestHeaders != nil {
|
||||||
|
|
@ -736,6 +874,7 @@ func convertConfig(ctx context.Context, model *Model) (*cdn.Config, error) {
|
||||||
OriginRequestHeaders: &originRequestHeaders,
|
OriginRequestHeaders: &originRequestHeaders,
|
||||||
OriginUrl: &configModel.Backend.OriginURL,
|
OriginUrl: &configModel.Backend.OriginURL,
|
||||||
Type: &configModel.Backend.Type,
|
Type: &configModel.Backend.Type,
|
||||||
|
Geofencing: &geofencing,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Regions: ®ions,
|
Regions: ®ions,
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,18 @@ func TestToCreatePayload(t *testing.T) {
|
||||||
"testHeader1": types.StringValue("testHeaderValue1"),
|
"testHeader1": types.StringValue("testHeaderValue1"),
|
||||||
}
|
}
|
||||||
originRequestHeaders := types.MapValueMust(types.StringType, headers)
|
originRequestHeaders := types.MapValueMust(types.StringType, headers)
|
||||||
|
geofencingCountries := types.ListValueMust(types.StringType, []attr.Value{
|
||||||
|
types.StringValue("DE"),
|
||||||
|
types.StringValue("FR"),
|
||||||
|
})
|
||||||
|
geofencing := types.MapValueMust(geofencingTypes.ElemType, map[string]attr.Value{
|
||||||
|
"https://de.mycoolapp.com": geofencingCountries,
|
||||||
|
})
|
||||||
backend := types.ObjectValueMust(backendTypes, map[string]attr.Value{
|
backend := types.ObjectValueMust(backendTypes, map[string]attr.Value{
|
||||||
"type": types.StringValue("http"),
|
"type": types.StringValue("http"),
|
||||||
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
||||||
"origin_request_headers": originRequestHeaders,
|
"origin_request_headers": originRequestHeaders,
|
||||||
|
"geofencing": geofencing,
|
||||||
})
|
})
|
||||||
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
||||||
regionsFixture := types.ListValueMust(types.StringType, regions)
|
regionsFixture := types.ListValueMust(types.StringType, regions)
|
||||||
|
|
@ -61,6 +69,9 @@ func TestToCreatePayload(t *testing.T) {
|
||||||
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
||||||
Regions: &[]cdn.Region{"EU", "US"},
|
Regions: &[]cdn.Region{"EU", "US"},
|
||||||
BlockedCountries: &[]string{"XX", "YY", "ZZ"},
|
BlockedCountries: &[]string{"XX", "YY", "ZZ"},
|
||||||
|
Geofencing: &map[string][]string{
|
||||||
|
"https://de.mycoolapp.com": {"DE", "FR"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
IsValid: true,
|
IsValid: true,
|
||||||
},
|
},
|
||||||
|
|
@ -82,6 +93,9 @@ func TestToCreatePayload(t *testing.T) {
|
||||||
Regions: &[]cdn.Region{"EU", "US"},
|
Regions: &[]cdn.Region{"EU", "US"},
|
||||||
Optimizer: cdn.NewOptimizer(true),
|
Optimizer: cdn.NewOptimizer(true),
|
||||||
BlockedCountries: &[]string{"XX", "YY", "ZZ"},
|
BlockedCountries: &[]string{"XX", "YY", "ZZ"},
|
||||||
|
Geofencing: &map[string][]string{
|
||||||
|
"https://de.mycoolapp.com": {"DE", "FR"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
IsValid: true,
|
IsValid: true,
|
||||||
},
|
},
|
||||||
|
|
@ -126,10 +140,18 @@ func TestConvertConfig(t *testing.T) {
|
||||||
"testHeader1": types.StringValue("testHeaderValue1"),
|
"testHeader1": types.StringValue("testHeaderValue1"),
|
||||||
}
|
}
|
||||||
originRequestHeaders := types.MapValueMust(types.StringType, headers)
|
originRequestHeaders := types.MapValueMust(types.StringType, headers)
|
||||||
|
geofencingCountries := types.ListValueMust(types.StringType, []attr.Value{
|
||||||
|
types.StringValue("DE"),
|
||||||
|
types.StringValue("FR"),
|
||||||
|
})
|
||||||
|
geofencing := types.MapValueMust(geofencingTypes.ElemType, map[string]attr.Value{
|
||||||
|
"https://de.mycoolapp.com": geofencingCountries,
|
||||||
|
})
|
||||||
backend := types.ObjectValueMust(backendTypes, map[string]attr.Value{
|
backend := types.ObjectValueMust(backendTypes, map[string]attr.Value{
|
||||||
"type": types.StringValue("http"),
|
"type": types.StringValue("http"),
|
||||||
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
||||||
"origin_request_headers": originRequestHeaders,
|
"origin_request_headers": originRequestHeaders,
|
||||||
|
"geofencing": geofencing,
|
||||||
})
|
})
|
||||||
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
||||||
regionsFixture := types.ListValueMust(types.StringType, regions)
|
regionsFixture := types.ListValueMust(types.StringType, regions)
|
||||||
|
|
@ -169,6 +191,9 @@ func TestConvertConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
||||||
Type: cdn.PtrString("http"),
|
Type: cdn.PtrString("http"),
|
||||||
|
Geofencing: &map[string][]string{
|
||||||
|
"https://de.mycoolapp.com": {"DE", "FR"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Regions: &[]cdn.Region{"EU", "US"},
|
Regions: &[]cdn.Region{"EU", "US"},
|
||||||
|
|
@ -194,6 +219,9 @@ func TestConvertConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
OriginUrl: cdn.PtrString("https://www.mycoolapp.com"),
|
||||||
Type: cdn.PtrString("http"),
|
Type: cdn.PtrString("http"),
|
||||||
|
Geofencing: &map[string][]string{
|
||||||
|
"https://de.mycoolapp.com": {"DE", "FR"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Regions: &[]cdn.Region{"EU", "US"},
|
Regions: &[]cdn.Region{"EU", "US"},
|
||||||
|
|
@ -246,11 +274,17 @@ func TestMapFields(t *testing.T) {
|
||||||
"type": types.StringValue("http"),
|
"type": types.StringValue("http"),
|
||||||
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
||||||
"origin_request_headers": originRequestHeaders,
|
"origin_request_headers": originRequestHeaders,
|
||||||
|
"geofencing": types.MapNull(geofencingTypes.ElemType),
|
||||||
})
|
})
|
||||||
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
regions := []attr.Value{types.StringValue("EU"), types.StringValue("US")}
|
||||||
regionsFixture := types.ListValueMust(types.StringType, regions)
|
regionsFixture := types.ListValueMust(types.StringType, regions)
|
||||||
blockedCountries := []attr.Value{types.StringValue("XX"), types.StringValue("YY"), types.StringValue("ZZ")}
|
blockedCountries := []attr.Value{types.StringValue("XX"), types.StringValue("YY"), types.StringValue("ZZ")}
|
||||||
blockedCountriesFixture := types.ListValueMust(types.StringType, blockedCountries)
|
blockedCountriesFixture := types.ListValueMust(types.StringType, blockedCountries)
|
||||||
|
geofencingCountries := types.ListValueMust(types.StringType, []attr.Value{types.StringValue("DE"), types.StringValue("BR")})
|
||||||
|
geofencing := types.MapValueMust(geofencingTypes.ElemType, map[string]attr.Value{
|
||||||
|
"test/": geofencingCountries,
|
||||||
|
})
|
||||||
|
geofencingInput := map[string][]string{"test/": {"DE", "BR"}}
|
||||||
optimizer := types.ObjectValueMust(optimizerTypes, map[string]attr.Value{
|
optimizer := types.ObjectValueMust(optimizerTypes, map[string]attr.Value{
|
||||||
"enabled": types.BoolValue(true),
|
"enabled": types.BoolValue(true),
|
||||||
})
|
})
|
||||||
|
|
@ -347,6 +381,26 @@ func TestMapFields(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
IsValid: true,
|
IsValid: true,
|
||||||
},
|
},
|
||||||
|
"happy_path_with_geofencing": {
|
||||||
|
Expected: expectedModel(func(m *Model) {
|
||||||
|
backendWithGeofencing := types.ObjectValueMust(backendTypes, map[string]attr.Value{
|
||||||
|
"type": types.StringValue("http"),
|
||||||
|
"origin_url": types.StringValue("https://www.mycoolapp.com"),
|
||||||
|
"origin_request_headers": originRequestHeaders,
|
||||||
|
"geofencing": geofencing,
|
||||||
|
})
|
||||||
|
m.Config = types.ObjectValueMust(configTypes, map[string]attr.Value{
|
||||||
|
"backend": backendWithGeofencing,
|
||||||
|
"regions": regionsFixture,
|
||||||
|
"optimizer": types.ObjectNull(optimizerTypes),
|
||||||
|
"blocked_countries": blockedCountriesFixture,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
Input: distributionFixture(func(d *cdn.Distribution) {
|
||||||
|
d.Config.Backend.HttpBackend.Geofencing = &geofencingInput
|
||||||
|
}),
|
||||||
|
IsValid: true,
|
||||||
|
},
|
||||||
"happy_path_status_error": {
|
"happy_path_status_error": {
|
||||||
Expected: expectedModel(func(m *Model) {
|
Expected: expectedModel(func(m *Model) {
|
||||||
m.Status = types.StringValue("ERROR")
|
m.Status = types.StringValue("ERROR")
|
||||||
|
|
@ -412,7 +466,7 @@ func TestMapFields(t *testing.T) {
|
||||||
for tn, tc := range tests {
|
for tn, tc := range tests {
|
||||||
t.Run(tn, func(t *testing.T) {
|
t.Run(tn, func(t *testing.T) {
|
||||||
model := &Model{}
|
model := &Model{}
|
||||||
err := mapFields(tc.Input, model)
|
err := mapFields(context.Background(), tc.Input, model)
|
||||||
if err != nil && tc.IsValid {
|
if err != nil && tc.IsValid {
|
||||||
t.Fatalf("Error mapping fields: %v", err)
|
t.Fatalf("Error mapping fields: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,19 @@ func SimplifyBackupSchedule(schedule string) string {
|
||||||
return simplifiedSchedule
|
return simplifiedSchedule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConvertPointerSliceToStringSlice safely converts a slice of string pointers to a slice of strings.
|
||||||
|
func ConvertPointerSliceToStringSlice(pointerSlice []*string) []string {
|
||||||
|
if pointerSlice == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
stringSlice := make([]string, 0, len(pointerSlice))
|
||||||
|
for _, strPtr := range pointerSlice {
|
||||||
|
if strPtr != nil { // Safely skip any nil pointers in the list
|
||||||
|
stringSlice = append(stringSlice, *strPtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringSlice
|
||||||
|
}
|
||||||
func SupportedValuesDocumentation(values []string) string {
|
func SupportedValuesDocumentation(values []string) string {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
|
||||||
|
"github.com/stackitcloud/stackit-sdk-go/core/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReconcileStrLists(t *testing.T) {
|
func TestReconcileStrLists(t *testing.T) {
|
||||||
|
|
@ -128,6 +129,55 @@ func TestListValuetoStrSlice(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertPointerSliceToStringSlice(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
description string
|
||||||
|
input []*string
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "nil slice",
|
||||||
|
input: nil,
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "empty slice",
|
||||||
|
input: []*string{},
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "slice with valid pointers",
|
||||||
|
input: []*string{utils.Ptr("apple"), utils.Ptr("banana"), utils.Ptr("cherry")},
|
||||||
|
expected: []string{"apple", "banana", "cherry"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "slice with some nil pointers",
|
||||||
|
input: []*string{utils.Ptr("apple"), nil, utils.Ptr("cherry"), nil},
|
||||||
|
expected: []string{"apple", "cherry"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "slice with all nil pointers",
|
||||||
|
input: []*string{nil, nil, nil},
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "slice with a pointer to an empty string",
|
||||||
|
input: []*string{utils.Ptr("apple"), utils.Ptr(""), utils.Ptr("cherry")},
|
||||||
|
expected: []string{"apple", "", "cherry"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.description, func(t *testing.T) {
|
||||||
|
output := ConvertPointerSliceToStringSlice(tt.input)
|
||||||
|
diff := cmp.Diff(output, tt.expected)
|
||||||
|
if diff != "" {
|
||||||
|
t.Fatalf("Data does not match: %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSimplifyBackupSchedule(t *testing.T) {
|
func TestSimplifyBackupSchedule(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
description string
|
description string
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue