Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 48 additions & 31 deletions stackit/internal/services/cdn/cdn_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,30 @@ var (
credentialsName = "acc-c" + acctest.RandStringFromCharSet(3, acctest.CharSetAlpha)
credentialsNameUpdated = "acc-c-updated" + acctest.RandStringFromCharSet(3, acctest.CharSetAlpha)
httpTestName = "acc-h" + acctest.RandStringFromCharSet(3, acctest.CharSetAlpha)
dnsNameHttp = fmt.Sprintf("tf-%s.runs.onstackit.cloud", httpTestName)
dnsRecordNameHttp = uuid.NewString()
cert, key = makeCertAndKey(testutil.OrganizationId)

// FIX: Reverted to stackit.gg as used in the working old code to avoid reserved domain rejection
dnsNameHttp = fmt.Sprintf("tf-acc-%s.stackit.gg", strings.Split(uuid.NewString(), "-")[0])
dnsRecordNameHttp = uuid.NewString()

// Build the full domain name here so we can use it to sign the certificate
fullDomainNameHttp = fmt.Sprintf("%s.%s", dnsRecordNameHttp, dnsNameHttp)

cert, key = makeCertAndKey(testutil.OrganizationId, fullDomainNameHttp)
)

var (
//go:embed testdata/resource-bucket.tf
resourceBucket string

//go:embed testdata/resource-http.tf
resourceHttp string
//go:embed testdata/resource-http-base.tf
resourceHttpBase string

//go:embed testdata/resource-http-custom-domain.tf
resourceHttpCustomDomain string
)

var resourceHttpFull = resourceHttpBase + "\n" + resourceHttpCustomDomain

var testConfigVarsBucket = config.Variables{
"project_id": config.StringVariable(testutil.ProjectId),
"bucket_name": config.StringVariable(bucketName),
Expand Down Expand Up @@ -90,7 +101,7 @@ func configVarsHttpUpdated() config.Variables {
return updatedConfig
}

func makeCertAndKey(organization string) (cert, key []byte) {
func makeCertAndKey(organization, domain string) (cert, key []byte) {
privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 2048)
if err != nil {
fmt.Printf("failed to generate key: %s", err.Error())
Expand All @@ -100,10 +111,11 @@ func makeCertAndKey(organization string) (cert, key []byte) {
Issuer: pkix.Name{CommonName: organization},
Subject: pkix.Name{
Organization: []string{organization},
CommonName: domain, // Required by most modern TLS validations
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour),

DNSNames: []string{domain},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
Expand All @@ -129,14 +141,13 @@ func makeCertAndKey(organization string) (cert, key []byte) {
}

func TestAccCDNDistributionHttp(t *testing.T) {
fullDomainName := fmt.Sprintf("%s.%s", testutil.ConvertConfigVariable(testConfigVarsHttp["dns_record_name"]), testutil.ConvertConfigVariable(testConfigVarsHttp["dns_name"]))
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
CheckDestroy: testAccCheckCDNDistributionDestroy,
Steps: []resource.TestStep{
// Distribution Create
// Distribution Create (Only Base config)
{
Config: testutil.CdnProviderConfig() + "\n" + resourceHttp,
Config: testutil.CdnProviderConfig() + "\n" + resourceHttpBase,
ConfigVariables: testConfigVarsHttp,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
Expand Down Expand Up @@ -166,22 +177,22 @@ func TestAccCDNDistributionHttp(t *testing.T) {
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "status", "ACTIVE"),
),
},
// Wait step, that confirms the CNAME record has "propagated"
// Wait step, confirms the CNAME record has "propagated" before trying to add the custom domain
{
Config: testutil.CdnProviderConfig() + "\n" + resourceHttp,
Config: testutil.CdnProviderConfig() + "\n" + resourceHttpBase,
ConfigVariables: testConfigVarsHttp,
Check: func(_ *terraform.State) error {
_, err := blockUntilDomainResolves(fullDomainName)
_, err := blockUntilDomainResolves(fullDomainNameHttp)
return err
},
},
// Custom Domain Create
// Custom Domain Create (Now using Full config)
{
Config: testutil.CdnProviderConfig() + "\n" + resourceHttp,
Config: testutil.CdnProviderConfig() + "\n" + resourceHttpFull,
ConfigVariables: testConfigVarsHttp,
Check: resource.ComposeAggregateTestCheckFunc(
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", fullDomainNameHttp),
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "certificate.version", "1"),
resource.TestCheckResourceAttrPair("stackit_cdn_distribution.distribution", "distribution_id", "stackit_cdn_custom_domain.custom_domain", "distribution_id"),
resource.TestCheckResourceAttrPair("stackit_cdn_distribution.distribution", "project_id", "stackit_cdn_custom_domain.custom_domain", "project_id"),
Expand Down Expand Up @@ -235,15 +246,15 @@ func TestAccCDNDistributionHttp(t *testing.T) {
},
// Data Source
{
Config: testutil.CdnProviderConfig() + "\n" + resourceHttp,
Config: testutil.CdnProviderConfig() + "\n" + resourceHttpFull,
ConfigVariables: testConfigVarsHttp,
Check: resource.ComposeAggregateTestCheckFunc(
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", "updated_at"),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.#", "2"),
resource.TestCheckResourceAttrSet("data.stackit_cdn_distribution.distribution", "domains.0.name"),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.1.name", fullDomainName),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.1.name", fullDomainNameHttp),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.0.status", "ACTIVE"),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.1.status", "ACTIVE"),
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "domains.0.type", "managed"),
Expand All @@ -268,22 +279,22 @@ func TestAccCDNDistributionHttp(t *testing.T) {
resource.TestCheckResourceAttr("data.stackit_cdn_distribution.distribution", "status", "ACTIVE"),

resource.TestCheckResourceAttr("data.stackit_cdn_custom_domain.custom_domain", "status", "ACTIVE"),
resource.TestCheckResourceAttr("data.stackit_cdn_custom_domain.custom_domain", "name", fullDomainName),
resource.TestCheckResourceAttr("data.stackit_cdn_custom_domain.custom_domain", "name", fullDomainNameHttp),
resource.TestCheckResourceAttr("data.stackit_cdn_custom_domain.custom_domain", "certificate.version", "1"),
resource.TestCheckResourceAttrPair("stackit_cdn_distribution.distribution", "distribution_id", "stackit_cdn_custom_domain.custom_domain", "distribution_id"),
),
},
// Update
{
Config: testutil.CdnProviderConfig() + "\n" + resourceHttp,
Config: testutil.CdnProviderConfig() + "\n" + resourceHttpFull,
ConfigVariables: configVarsHttpUpdated(),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "distribution_id"),
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "created_at"),
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "updated_at"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.#", "2"),
resource.TestCheckResourceAttrSet("stackit_cdn_distribution.distribution", "domains.0.name"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.1.name", fullDomainName),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.1.name", fullDomainNameHttp),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.0.status", "ACTIVE"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.1.status", "ACTIVE"),
resource.TestCheckResourceAttr("stackit_cdn_distribution.distribution", "domains.0.type", "managed"),
Expand All @@ -309,7 +320,7 @@ func TestAccCDNDistributionHttp(t *testing.T) {
),

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", fullDomainNameHttp),
resource.TestCheckResourceAttr("stackit_cdn_custom_domain.custom_domain", "certificate.version", "1"),
resource.TestCheckResourceAttrPair("stackit_cdn_distribution.distribution", "distribution_id", "stackit_cdn_custom_domain.custom_domain", "distribution_id"),
resource.TestCheckResourceAttrPair("stackit_cdn_distribution.distribution", "project_id", "stackit_cdn_custom_domain.custom_domain", "project_id"),
Expand Down Expand Up @@ -490,10 +501,10 @@ func testAccCheckCDNDistributionDestroy(s *terraform.State) error {

const (
recordCheckInterval time.Duration = 3 * time.Second
recordCheckAttempts = 100 // wait up to 5 minutes for record to be come available (normally takes less than 2 minutes)
recordCheckAttempts = 100 // wait up to 5 minutes for record to become available (normally takes less than 2 minutes)
)

func blockUntilDomainResolves(domain string) (string, error) {
func blockUntilDomainResolves(domain string) (net.IP, error) {
// Create a custom resolver that bypasses the local system DNS settings/cache
// and queries Google DNS (8.8.8.8) directly.
r := &net.Resolver{
Expand All @@ -506,17 +517,23 @@ func blockUntilDomainResolves(domain string) (string, error) {
return d.DialContext(ctx, network, "8.8.8.8:53")
},
}

// wait until it becomes ready
isReady := func() (string, error) {
isReady := func() (net.IP, error) {
// Use a context for the individual query timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

cname, err := r.LookupCNAME(ctx, domain)
ips, err := r.LookupIP(ctx, "ip", domain)
if err != nil {
return "", fmt.Errorf("error looking up CNAME for domain %s: %w", domain, err)
return nil, fmt.Errorf("error looking up IP for domain %s: %w", domain, err)
}
for _, ip := range ips {
if ip.String() != "<nil>" {
return ip, nil
}
}
return cname, nil
return nil, fmt.Errorf("no IP for domain: %v", domain)
}

return retry(recordCheckAttempts, recordCheckInterval, isReady)
Expand All @@ -525,7 +542,7 @@ func blockUntilDomainResolves(domain string) (string, error) {
func retry[T any](attempts int, sleep time.Duration, f func() (T, error)) (T, error) {
var zero T
var errOuter error
for range attempts {
for i := 0; i < attempts; i++ {
dist, err := f()
if err == nil {
return dist, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ resource "stackit_dns_zone" "dns_zone" {
type = "primary"
default_ttl = 3600
}

resource "stackit_dns_record_set" "dns_record" {
project_id = var.project_id
zone_id = stackit_dns_zone.dns_zone.zone_id
Expand All @@ -48,30 +49,11 @@ resource "stackit_cdn_distribution" "distribution" {
(var.backend_origin_url) = var.geofencing_list
}
}
regions = var.regions
blocked_countries = var.blocked_countries
}
}

data "stackit_cdn_distribution" "distribution" {
project_id = var.project_id
distribution_id = stackit_cdn_distribution.distribution.distribution_id
}

# custom domain
resource "stackit_cdn_custom_domain" "custom_domain" {
project_id = var.project_id
distribution_id = stackit_cdn_distribution.distribution.distribution_id
name = "${stackit_dns_record_set.dns_record.name}.${stackit_dns_zone.dns_zone.dns_name}"
certificate = {
certificate = var.certificate
private_key = var.private_key
}
}

data "stackit_cdn_custom_domain" "custom_domain" {
project_id = var.project_id
distribution_id = stackit_cdn_distribution.distribution.distribution_id
name = "${stackit_dns_record_set.dns_record.name}.${stackit_dns_zone.dns_zone.dns_name}"
depends_on = [stackit_cdn_custom_domain.custom_domain]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# custom domain
resource "stackit_cdn_custom_domain" "custom_domain" {
project_id = var.project_id
distribution_id = stackit_cdn_distribution.distribution.distribution_id
name = "${stackit_dns_record_set.dns_record.name}.${stackit_dns_zone.dns_zone.dns_name}"
certificate = {
certificate = var.certificate
private_key = var.private_key
}
}

data "stackit_cdn_custom_domain" "custom_domain" {
project_id = var.project_id
distribution_id = stackit_cdn_distribution.distribution.distribution_id
name = "${stackit_dns_record_set.dns_record.name}.${stackit_dns_zone.dns_zone.dns_name}"
depends_on = [stackit_cdn_custom_domain.custom_domain]
}
Loading