Skip to content

Commit 55dc96d

Browse files
Merge pull request #5888 from cfjubacf/spectrum-drift-and-new-tests
Add additional Spectrum tests and fix drift
2 parents 3261d1c + 1cc94d4 commit 55dc96d

12 files changed

+437
-10
lines changed

internal/services/spectrum_application/resource.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (r *SpectrumApplicationResource) Read(ctx context.Context, req resource.Rea
174174
return
175175
}
176176
bytes, _ := io.ReadAll(res.Body)
177-
err = apijson.Unmarshal(bytes, &env)
177+
err = apijson.UnmarshalComputed(bytes, &env)
178178
if err != nil {
179179
resp.Diagnostics.AddError("failed to deserialize http request", err.Error())
180180
return
@@ -244,7 +244,7 @@ func (r *SpectrumApplicationResource) ImportState(ctx context.Context, req resou
244244
return
245245
}
246246
bytes, _ := io.ReadAll(res.Body)
247-
err = apijson.Unmarshal(bytes, &env)
247+
err = apijson.UnmarshalComputed(bytes, &env)
248248
if err != nil {
249249
resp.Diagnostics.AddError("failed to deserialize http request", err.Error())
250250
return

internal/services/spectrum_application/resource_test.go

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,234 @@ func TestAccCloudflareSpectrumApplication_BasicMinecraft(t *testing.T) {
314314
})
315315
}
316316

317+
func TestAccCloudflareSpectrumApplication_TLS(t *testing.T) {
318+
var spectrumApp cloudflare.SpectrumApplication
319+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
320+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
321+
rnd := utils.GenerateRandomResourceName()
322+
name := "cloudflare_spectrum_application." + rnd
323+
324+
resource.Test(t, resource.TestCase{
325+
PreCheck: func() { acctest.TestAccPreCheck(t) },
326+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
327+
Steps: []resource.TestStep{
328+
{
329+
Config: testAccCheckCloudflareSpectrumApplicationConfigTLS(zoneID, domain, rnd, "flexible"),
330+
Check: resource.ComposeTestCheckFunc(
331+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
332+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
333+
resource.TestCheckResourceAttr(name, "tls", "flexible"),
334+
),
335+
},
336+
{
337+
Config: testAccCheckCloudflareSpectrumApplicationConfigTLS(zoneID, domain, rnd, "full"),
338+
Check: resource.ComposeTestCheckFunc(
339+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
340+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
341+
resource.TestCheckResourceAttr(name, "tls", "full"),
342+
),
343+
},
344+
{
345+
Config: testAccCheckCloudflareSpectrumApplicationConfigTLS(zoneID, domain, rnd, "strict"),
346+
Check: resource.ComposeTestCheckFunc(
347+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
348+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
349+
resource.TestCheckResourceAttr(name, "tls", "strict"),
350+
),
351+
},
352+
},
353+
})
354+
}
355+
356+
func TestAccCloudflareSpectrumApplication_ProxyProtocol(t *testing.T) {
357+
var spectrumApp cloudflare.SpectrumApplication
358+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
359+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
360+
rnd := utils.GenerateRandomResourceName()
361+
name := "cloudflare_spectrum_application." + rnd
362+
363+
resource.Test(t, resource.TestCase{
364+
PreCheck: func() { acctest.TestAccPreCheck(t) },
365+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
366+
Steps: []resource.TestStep{
367+
{
368+
Config: testAccCheckCloudflareSpectrumApplicationConfigProxyProtocol(zoneID, domain, rnd, "v1"),
369+
Check: resource.ComposeTestCheckFunc(
370+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
371+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
372+
resource.TestCheckResourceAttr(name, "proxy_protocol", "v1"),
373+
),
374+
},
375+
{
376+
Config: testAccCheckCloudflareSpectrumApplicationConfigProxyProtocol(zoneID, domain, rnd, "v2"),
377+
Check: resource.ComposeTestCheckFunc(
378+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
379+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
380+
resource.TestCheckResourceAttr(name, "proxy_protocol", "v2"),
381+
),
382+
},
383+
},
384+
})
385+
}
386+
387+
func TestAccCloudflareSpectrumApplication_IPFirewall(t *testing.T) {
388+
var spectrumApp cloudflare.SpectrumApplication
389+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
390+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
391+
rnd := utils.GenerateRandomResourceName()
392+
name := "cloudflare_spectrum_application." + rnd
393+
394+
resource.Test(t, resource.TestCase{
395+
PreCheck: func() { acctest.TestAccPreCheck(t) },
396+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
397+
Steps: []resource.TestStep{
398+
{
399+
Config: testAccCheckCloudflareSpectrumApplicationConfigIPFirewall(zoneID, domain, rnd, "true"),
400+
Check: resource.ComposeTestCheckFunc(
401+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
402+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
403+
resource.TestCheckResourceAttr(name, "ip_firewall", "true"),
404+
),
405+
},
406+
{
407+
Config: testAccCheckCloudflareSpectrumApplicationConfigIPFirewall(zoneID, domain, rnd, "false"),
408+
Check: resource.ComposeTestCheckFunc(
409+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
410+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
411+
resource.TestCheckResourceAttr(name, "ip_firewall", "false"),
412+
),
413+
},
414+
},
415+
})
416+
}
417+
418+
func TestAccCloudflareSpectrumApplication_ArgoSmartRouting(t *testing.T) {
419+
var spectrumApp cloudflare.SpectrumApplication
420+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
421+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
422+
rnd := utils.GenerateRandomResourceName()
423+
name := "cloudflare_spectrum_application." + rnd
424+
425+
resource.Test(t, resource.TestCase{
426+
PreCheck: func() { acctest.TestAccPreCheck(t) },
427+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
428+
Steps: []resource.TestStep{
429+
{
430+
Config: testAccCheckCloudflareSpectrumApplicationConfigArgoSmartRouting(zoneID, domain, rnd, "true"),
431+
Check: resource.ComposeTestCheckFunc(
432+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
433+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
434+
resource.TestCheckResourceAttr(name, "argo_smart_routing", "true"),
435+
resource.TestCheckResourceAttr(name, "traffic_type", "direct"),
436+
),
437+
},
438+
{
439+
Config: testAccCheckCloudflareSpectrumApplicationConfigArgoSmartRouting(zoneID, domain, rnd, "false"),
440+
Check: resource.ComposeTestCheckFunc(
441+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
442+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
443+
resource.TestCheckResourceAttr(name, "argo_smart_routing", "false"),
444+
resource.TestCheckResourceAttr(name, "traffic_type", "direct"),
445+
),
446+
},
447+
},
448+
})
449+
}
450+
451+
func TestAccCloudflareSpectrumApplication_TrafficType(t *testing.T) {
452+
var spectrumApp cloudflare.SpectrumApplication
453+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
454+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
455+
rnd := utils.GenerateRandomResourceName()
456+
name := "cloudflare_spectrum_application." + rnd
457+
458+
resource.Test(t, resource.TestCase{
459+
PreCheck: func() { acctest.TestAccPreCheck(t) },
460+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
461+
Steps: []resource.TestStep{
462+
{
463+
Config: testAccCheckCloudflareSpectrumApplicationConfigTrafficType(zoneID, domain, rnd, "http"),
464+
Check: resource.ComposeTestCheckFunc(
465+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
466+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
467+
resource.TestCheckResourceAttr(name, "traffic_type", "http"),
468+
),
469+
},
470+
{
471+
Config: testAccCheckCloudflareSpectrumApplicationConfigTrafficType(zoneID, domain, rnd, "https"),
472+
Check: resource.ComposeTestCheckFunc(
473+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
474+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
475+
resource.TestCheckResourceAttr(name, "traffic_type", "https"),
476+
),
477+
},
478+
{
479+
Config: testAccCheckCloudflareSpectrumApplicationConfigTrafficType(zoneID, domain, rnd, "direct"),
480+
Check: resource.ComposeTestCheckFunc(
481+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
482+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
483+
resource.TestCheckResourceAttr(name, "traffic_type", "direct"),
484+
),
485+
},
486+
},
487+
})
488+
}
489+
490+
func TestAccCloudflareSpectrumApplication_IPv6Connectivity(t *testing.T) {
491+
var spectrumApp cloudflare.SpectrumApplication
492+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
493+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
494+
rnd := utils.GenerateRandomResourceName()
495+
name := "cloudflare_spectrum_application." + rnd
496+
497+
resource.Test(t, resource.TestCase{
498+
PreCheck: func() { acctest.TestAccPreCheck(t) },
499+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
500+
Steps: []resource.TestStep{
501+
{
502+
Config: testAccCheckCloudflareSpectrumApplicationConfigIPv6(zoneID, domain, rnd),
503+
Check: resource.ComposeTestCheckFunc(
504+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
505+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
506+
resource.TestCheckResourceAttr(name, "edge_ips.connectivity", "ipv6"),
507+
),
508+
},
509+
},
510+
})
511+
}
512+
513+
func TestAccCloudflareSpectrumApplication_UDP(t *testing.T) {
514+
var spectrumApp cloudflare.SpectrumApplication
515+
domain := os.Getenv("CLOUDFLARE_DOMAIN")
516+
zoneID := os.Getenv("CLOUDFLARE_ZONE_ID")
517+
rnd := utils.GenerateRandomResourceName()
518+
name := "cloudflare_spectrum_application." + rnd
519+
520+
resource.Test(t, resource.TestCase{
521+
PreCheck: func() { acctest.TestAccPreCheck(t) },
522+
ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
523+
Steps: []resource.TestStep{
524+
{
525+
Config: testAccCheckCloudflareSpectrumApplicationConfigUDP(zoneID, domain, rnd),
526+
Check: resource.ComposeTestCheckFunc(
527+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
528+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
529+
resource.TestCheckResourceAttr(name, "protocol", "udp/53"),
530+
resource.TestCheckResourceAttr(name, "traffic_type", "direct"),
531+
),
532+
},
533+
{
534+
Config: testAccCheckCloudflareSpectrumApplicationConfigSimpleProxyProtocol(zoneID, domain, rnd),
535+
Check: resource.ComposeTestCheckFunc(
536+
testAccCheckCloudflareSpectrumApplicationExists(name, &spectrumApp),
537+
testAccCheckCloudflareSpectrumApplicationIDIsValid(name),
538+
resource.TestCheckResourceAttr(name, "proxy_protocol", "simple"),
539+
),
540+
},
541+
},
542+
})
543+
}
544+
317545
func testAccCheckCloudflareSpectrumApplicationExists(n string, spectrumApp *cloudflare.SpectrumApplication) resource.TestCheckFunc {
318546
return func(s *terraform.State) error {
319547
rs, ok := s.RootModule().Resources[n]
@@ -409,3 +637,35 @@ func testAccCheckCloudflareSpectrumApplicationConfigMultipleEdgeIPs(zoneID, zone
409637
func testAccCheckCloudflareSpectrumApplicationConfigBasicTypes(zoneID, zoneName, ID, protocol string, port int) string {
410638
return acctest.LoadTestCase("spectrumapplicationconfigbasictypes.tf", zoneID, zoneName, ID, protocol, port)
411639
}
640+
641+
func testAccCheckCloudflareSpectrumApplicationConfigTLS(zoneID, zoneName, ID, tls string) string {
642+
return acctest.LoadTestCase("spectrumapplicationconfigtls.tf", zoneID, zoneName, ID, tls)
643+
}
644+
645+
func testAccCheckCloudflareSpectrumApplicationConfigProxyProtocol(zoneID, zoneName, ID, proxyProtocol string) string {
646+
return acctest.LoadTestCase("spectrumapplicationconfigproxyprotocol.tf", zoneID, zoneName, ID, proxyProtocol)
647+
}
648+
649+
func testAccCheckCloudflareSpectrumApplicationConfigSimpleProxyProtocol(zoneID, zoneName, ID string) string {
650+
return acctest.LoadTestCase("spectrumapplicationconfigsimpleproxyprotocol.tf", zoneID, zoneName, ID)
651+
}
652+
653+
func testAccCheckCloudflareSpectrumApplicationConfigIPFirewall(zoneID, zoneName, ID, ipFirewall string) string {
654+
return acctest.LoadTestCase("spectrumapplicationconfigipfirewall.tf", zoneID, zoneName, ID, ipFirewall)
655+
}
656+
657+
func testAccCheckCloudflareSpectrumApplicationConfigArgoSmartRouting(zoneID, zoneName, ID, argoSmartRouting string) string {
658+
return acctest.LoadTestCase("spectrumapplicationconfigargosmartrouting.tf", zoneID, zoneName, ID, argoSmartRouting)
659+
}
660+
661+
func testAccCheckCloudflareSpectrumApplicationConfigTrafficType(zoneID, zoneName, ID, trafficType string) string {
662+
return acctest.LoadTestCase("spectrumapplicationconfigtraffictype.tf", zoneID, zoneName, ID, trafficType)
663+
}
664+
665+
func testAccCheckCloudflareSpectrumApplicationConfigIPv6(zoneID, zoneName, ID string) string {
666+
return acctest.LoadTestCase("spectrumapplicationconfigipv6.tf", zoneID, zoneName, ID)
667+
}
668+
669+
func testAccCheckCloudflareSpectrumApplicationConfigUDP(zoneID, zoneName, ID string) string {
670+
return acctest.LoadTestCase("spectrumapplicationconfigudp.tf", zoneID, zoneName, ID)
671+
}

internal/services/spectrum_application/schema.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/hashicorp/terraform-plugin-framework/resource"
1414
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
1515
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
16+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
1617
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1718
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
1819
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
@@ -58,11 +59,15 @@ func ResourceSchema(ctx context.Context) schema.Schema {
5859
},
5960
},
6061
"ip_firewall": schema.BoolAttribute{
62+
Computed: true,
6163
Description: "Enables IP Access Rules for this application.\nNotes: Only available for TCP applications.",
64+
Default: booldefault.StaticBool(false),
6265
Optional: true,
6366
},
6467
"tls": schema.StringAttribute{
68+
Computed: true,
6569
Description: "The type of TLS termination associated with the application.\nAvailable values: \"off\", \"flexible\", \"full\", \"strict\".",
70+
Default: stringdefault.StaticString("off"),
6671
Optional: true,
6772
Validators: []validator.String{
6873
stringvalidator.OneOfCaseInsensitive(
@@ -121,14 +126,16 @@ func ResourceSchema(ctx context.Context) schema.Schema {
121126
PlanModifiers: []planmodifier.Dynamic{customfield.NormalizeDynamicPlanModifier()},
122127
},
123128
"argo_smart_routing": schema.BoolAttribute{
124-
Description: "Enables Argo Smart Routing for this application.\nNotes: Only available for TCP applications with traffic_type set to \"direct\".",
125-
Computed: true,
126-
Optional: true,
127-
Default: booldefault.StaticBool(false),
129+
Computed: true,
130+
Default: booldefault.StaticBool(false),
131+
Description: "Enables Argo Smart Routing for this application.\nNotes: Only available for TCP applications with traffic_type set to \"direct\".",
132+
Optional: true,
133+
PlanModifiers: []planmodifier.Bool{boolplanmodifier.UseStateForUnknown()},
128134
},
129135
"proxy_protocol": schema.StringAttribute{
130-
Description: "Enables Proxy Protocol to the origin. Refer to [Enable Proxy protocol](https://developers.cloudflare.com/spectrum/getting-started/proxy-protocol/) for implementation details on PROXY Protocol V1, PROXY Protocol V2, and Simple Proxy Protocol.\nAvailable values: \"off\", \"v1\", \"v2\", \"simple\".",
131136
Computed: true,
137+
Default: stringdefault.StaticString("off"),
138+
Description: "Enables Proxy Protocol to the origin. Refer to [Enable Proxy protocol](https://developers.cloudflare.com/spectrum/getting-started/proxy-protocol/) for implementation details on PROXY Protocol V1, PROXY Protocol V2, and Simple Proxy Protocol.\nAvailable values: \"off\", \"v1\", \"v2\", \"simple\".",
132139
Optional: true,
133140
Validators: []validator.String{
134141
stringvalidator.OneOfCaseInsensitive(
@@ -138,7 +145,7 @@ func ResourceSchema(ctx context.Context) schema.Schema {
138145
"simple",
139146
),
140147
},
141-
Default: stringdefault.StaticString("off"),
148+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
142149
},
143150
"traffic_type": schema.StringAttribute{
144151
Description: "Determines how data travels from the edge to your origin. When set to \"direct\", Spectrum will send traffic directly to your origin, and the application's type is derived from the `protocol`. When set to \"http\" or \"https\", Spectrum will apply Cloudflare's HTTP/HTTPS features as it sends traffic to your origin, and the application type matches this property exactly.\nAvailable values: \"direct\", \"http\", \"https\".",
@@ -151,7 +158,8 @@ func ResourceSchema(ctx context.Context) schema.Schema {
151158
"https",
152159
),
153160
},
154-
Default: stringdefault.StaticString("direct"),
161+
Default: stringdefault.StaticString("direct"),
162+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
155163
},
156164
"edge_ips": schema.SingleNestedAttribute{
157165
Description: "The anycast edge IP configuration for the hostname of this application.",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
resource "cloudflare_spectrum_application" "%[3]s" {
2+
zone_id = "%[1]s"
3+
protocol = "tcp/22"
4+
5+
dns = {
6+
type = "CNAME"
7+
name = "%[3]s.%[2]s"
8+
}
9+
10+
origin_direct = ["tcp://128.66.0.8:22"]
11+
origin_port = 22
12+
13+
# Test Argo Smart Routing configuration
14+
argo_smart_routing = %[4]s # true or false
15+
traffic_type = "direct" # Required for Argo Smart Routing
16+
17+
edge_ips = {
18+
type = "dynamic"
19+
connectivity = "all"
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
resource "cloudflare_spectrum_application" "%[3]s" {
2+
zone_id = "%[1]s"
3+
protocol = "tcp/22"
4+
5+
dns = {
6+
type = "CNAME"
7+
name = "%[3]s.%[2]s"
8+
}
9+
10+
origin_direct = ["tcp://128.66.0.7:22"]
11+
origin_port = 22
12+
13+
# Test IP firewall configuration
14+
ip_firewall = %[4]s # true or false
15+
16+
edge_ips = {
17+
type = "dynamic"
18+
connectivity = "all"
19+
}
20+
}

0 commit comments

Comments
 (0)