Skip to content

Commit

Permalink
feat: add bYOIPv6 + endpoint + Destination IP support at locations
Browse files Browse the repository at this point in the history
  • Loading branch information
Rex Scaria committed Jan 3, 2025
1 parent 5547898 commit 132d89b
Show file tree
Hide file tree
Showing 5 changed files with 427 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .changelog/4805.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
cloudflare_teams_location: support endpoints + BYOIPv6 + DNS Ipv4 destinations
```
20 changes: 20 additions & 0 deletions docs/resources/teams_location.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ resource "cloudflare_teams_location" "example" {
networks {
network = "203.0.113.2/32"
}
dns_destination_ips_id = "0e4a32c6-6fb8-4858-9296-98f51631e8e6"
endpoints {
ipv4 {
enabled = true
}
ipv6 {
enabled = true
networks = [ { network = "2a09:bac5:50c3:400::6b:57/128" } ]
}
dot {
enabled = true
networks = [ { network = "2.5.6.201/32" } ]
}
doh {
enabled = true
networks = [ { network = "2.5.6.202/32" }, { network = "3.5.6.203/32" } ]
}
}
}
```
<!-- schema generated by tfplugindocs -->
Expand Down
228 changes: 225 additions & 3 deletions internal/sdkv2provider/resource_cloudflare_teams_location.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func resourceCloudflareTeamsLocationRead(ctx context.Context, d *schema.Resource
if err := d.Set("networks", flattenTeamsLocationNetworks(location.Networks)); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location networks"))
}

if err := d.Set("ip", location.Ip); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location IP"))
}
Expand All @@ -80,12 +81,26 @@ func resourceCloudflareTeamsLocationRead(ctx context.Context, d *schema.Resource
if err := d.Set("ipv4_destination", location.IPv4Destination); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location IPv4 destination"))
}
if err := d.Set("ipv4_destination_backup", location.IPv4DestinationBackup); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location IPv4 destination"))
}
if err := d.Set("client_default", location.ClientDefault); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location client default"))
}
if err := d.Set("ecs_support", location.ECSSupport); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location ecs support"))
}
if err := d.Set("dns_destination_ipv6_block_id", location.DNSDestinationIPv6BlockID); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location dns_destination_ipv6_block_id"))
}

if err := d.Set("dns_destination_ips_id", location.DNSDestinationIPsID); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location dns_destination_ipv6_block_id"))
}

if err := d.Set("endpoints", flattenTeamsEndpoints(location.Endpoints)); err != nil {
return diag.FromErr(fmt.Errorf("error parsing Location endpoints"))
}

return nil
}
Expand All @@ -97,14 +112,29 @@ func resourceCloudflareTeamsLocationCreate(ctx context.Context, d *schema.Resour
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Teams Location for account %q: %w, %v", accountID, err, networks))
}

newTeamLocation := cloudflare.TeamsLocation{
Name: d.Get("name").(string),
Networks: networks,
ClientDefault: d.Get("client_default").(bool),
ECSSupport: cloudflare.BoolPtr(d.Get("ecs_support").(bool)),
}

endpoints, err := inflateTeamsLocationEndpoint(d.Get("endpoints"))
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Teams Location endpoints for account %q: %w, %v", accountID, err, networks))
} else if endpoints != nil {
newTeamLocation.Endpoints = endpoints
}

destinationIpId, ok := d.Get("dns_destination_ips_id").(string)
if ok && destinationIpId != "" {
newTeamLocation.DNSDestinationIPsID = &destinationIpId
}
destinationIpv6Id, ok := d.Get("dns_destination_ipv6_block_id").(string)
if ok && destinationIpv6Id != "" {
newTeamLocation.DNSDestinationIPv6BlockID = &destinationIpv6Id
}

tflog.Debug(ctx, fmt.Sprintf("Creating Cloudflare Teams Location from struct: %+v", newTeamLocation))

location, err := client.CreateTeamsLocation(ctx, accountID, newTeamLocation)
Expand Down Expand Up @@ -188,21 +218,213 @@ func inflateTeamsLocationNetworks(networks interface{}) ([]cloudflare.TeamsLocat
return nil, fmt.Errorf("error parsing network")
}
networkStructs = append(networkStructs, cloudflare.TeamsLocationNetwork{
ID: network["id"].(string),
Network: network["network"].(string),
})
}
}
return networkStructs, nil
}

func inflateTeamsLocationNetworksFromList(networks interface{}) ([]cloudflare.TeamsLocationNetwork, error) {
var networkStructs []cloudflare.TeamsLocationNetwork
if networks != nil {
networkList, ok := networks.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing network list")
}
for _, i := range networkList {
network, ok := i.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("error parsing network")
}
networkStructs = append(networkStructs, cloudflare.TeamsLocationNetwork{
Network: network["network"].(string),
})
}
}
return networkStructs, nil
}

func inflateTeamsLocationEndpoint(endpoint interface{}) (*cloudflare.TeamsLocationEndpoints, error) {
if endpoint == nil {
return nil, nil
}

epList, ok := endpoint.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint list")
}
for _, i := range epList {
epItem, ok := i.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint")
}
ipv4Endpoint, err := inflateIpv4Endpoint(epItem["ipv4"])
if err != nil {
return nil, fmt.Errorf("error parsing ipv4 endpoint")
}

ipv6Endpoint, err := inflateIpv6Endpoint(epItem["ipv6"])
if err != nil {
return nil, fmt.Errorf("error parsing ipv6 endpoint")
}

dotEndpoint, err := inflateDoTEndpoint(epItem["dot"])
if err != nil {
return nil, fmt.Errorf("error parsing dot endpoint")
}

dohEndpoint, err := inflateDohEndpoint(epItem["doh"])
if err != nil {
return nil, fmt.Errorf("error parsing doh endpoint")
}

return &cloudflare.TeamsLocationEndpoints{
IPv4Endpoint: *ipv4Endpoint,
IPv6Endpoint: *ipv6Endpoint,
DotEndpoint: *dotEndpoint,
DohEndpoint: *dohEndpoint,
}, nil
}
return nil, fmt.Errorf("empty endpoint")
}

func inflateIpv4Endpoint(item interface{}) (*cloudflare.TeamsLocationIPv4EndpointFields, error) {
epItems, ok := item.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint item")
}

return &cloudflare.TeamsLocationIPv4EndpointFields{
Enabled: firstItemInSet(epItems)["enabled"].(bool),
}, nil
}

func firstItemInSet(l []interface{}) map[string]interface{} {
return l[0].(map[string]interface{})
}

func inflateIpv6Endpoint(item interface{}) (*cloudflare.TeamsLocationIPv6EndpointFields, error) {
epItems, ok := item.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint item")
}

epItem := firstItemInSet(epItems)

networks, err := inflateTeamsLocationNetworksFromList(epItem["networks"])
if err != nil {
return nil, fmt.Errorf("error parsing endpoint ipv6 networks")
}
return &cloudflare.TeamsLocationIPv6EndpointFields{
TeamsLocationEndpointFields: cloudflare.TeamsLocationEndpointFields{
Enabled: epItem["enabled"].(bool),
Networks: networks,
},
}, nil
}

func inflateDoTEndpoint(item interface{}) (*cloudflare.TeamsLocationDotEndpointFields, error) {
epItems, ok := item.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint item")
}

epItem := firstItemInSet(epItems)
networks, err := inflateTeamsLocationNetworksFromList(epItem["networks"])
if err != nil {
return nil, fmt.Errorf("error parsing endpoint dot networks")
}
return &cloudflare.TeamsLocationDotEndpointFields{
RequireToken: epItem["require_token"].(bool),
TeamsLocationEndpointFields: cloudflare.TeamsLocationEndpointFields{
Enabled: epItem["enabled"].(bool),
Networks: networks,
},
}, nil
}

func inflateDohEndpoint(item interface{}) (*cloudflare.TeamsLocationDohEndpointFields, error) {
epItems, ok := item.([]interface{})
if !ok {
return nil, fmt.Errorf("error parsing endpoint item")
}

epItem := firstItemInSet(epItems)

networks, err := inflateTeamsLocationNetworksFromList(epItem["networks"])
if err != nil {
return nil, fmt.Errorf("error parsing endpoint dot networks")
}
return &cloudflare.TeamsLocationDohEndpointFields{
RequireToken: epItem["require_token"].(bool),
TeamsLocationEndpointFields: cloudflare.TeamsLocationEndpointFields{
Enabled: epItem["enabled"].(bool),
Networks: networks,
},
}, nil
}

func flattenTeamsLocationNetworks(networks []cloudflare.TeamsLocationNetwork) []interface{} {
var flattenedNetworks []interface{}
for _, net := range networks {
flattenedNetworks = append(flattenedNetworks, map[string]interface{}{
"id": net.ID,
"network": net.Network,
})
}
return flattenedNetworks
}

func flattenTeamsLocationNetworksIntoList(networks []cloudflare.TeamsLocationNetwork) []interface{} {
var flattenedNetworks []interface{}
for _, net := range networks {
flattenedNetworks = append(flattenedNetworks, map[string]interface{}{
"network": net.Network,
})
}
return flattenedNetworks
}

func flattenTeamsEndpoints(endpoint *cloudflare.TeamsLocationEndpoints) []interface{} {
flattenedEndpoints := map[string]interface{}{
"ipv4": flattenTeamsEndpointIpv4Field(endpoint.IPv4Endpoint),
"ipv6": flattenTeamsEndpointIpv6Field(endpoint.IPv6Endpoint),
"doh": flattenTeamsEndpointDOHField(endpoint.DohEndpoint),
"dot": flattenTeamsEndpointDOTField(endpoint.DotEndpoint),
}
return []interface{}{flattenedEndpoints}

}

Check failure on line 397 in internal/sdkv2provider/resource_cloudflare_teams_location.go

View workflow job for this annotation

GitHub Actions / golangci-lint

unnecessary trailing newline (whitespace)

func flattenTeamsEndpointIpv4Field(field cloudflare.TeamsLocationIPv4EndpointFields) []map[string]interface{} {
return []map[string]interface{}{{
"enabled": field.Enabled,
"authentication_enabled": field.AuthenticationEnabled,
}}
}

func flattenTeamsEndpointIpv6Field(field cloudflare.TeamsLocationIPv6EndpointFields) []map[string]interface{} {
return []map[string]interface{}{{
"enabled": field.Enabled,
"authentication_enabled": field.AuthenticationEnabledUIHelper,
"networks": flattenTeamsLocationNetworksIntoList(field.Networks),
}}
}

func flattenTeamsEndpointDOTField(field cloudflare.TeamsLocationDotEndpointFields) []map[string]interface{} {
return []map[string]interface{}{{
"require_token": field.RequireToken,
"enabled": field.Enabled,
"authentication_enabled": field.AuthenticationEnabledUIHelper,
"networks": flattenTeamsLocationNetworksIntoList(field.Networks),
}}
}

func flattenTeamsEndpointDOHField(field cloudflare.TeamsLocationDohEndpointFields) []map[string]interface{} {
return []map[string]interface{}{{
"require_token": field.RequireToken,
"enabled": field.Enabled,
"authentication_enabled": field.AuthenticationEnabledUIHelper,
"networks": flattenTeamsLocationNetworksIntoList(field.Networks),
}}
}
39 changes: 39 additions & 0 deletions internal/sdkv2provider/resource_cloudflare_teams_location_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ func TestAccCloudflareTeamsLocationBasic(t *testing.T) {
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "client_default", "false"),
resource.TestCheckResourceAttr(name, "ecs_support", "false"),
resource.TestCheckResourceAttr(name, "networks.#", "1"),
resource.TestCheckResourceAttr(name, "networks.0.network", "2.5.6.200/32"),
resource.TestCheckResourceAttr(name, "endpoints.#", "1"),
resource.TestCheckResourceAttr(name, "endpoints.0.ipv4.0.enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.ipv4.0.authentication_enabled", "true"),

resource.TestCheckResourceAttr(name, "endpoints.0.ipv6.0.enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.ipv6.0.authentication_enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.ipv6.0.networks.0.network", "2a09:bac5:50c3:400::6b:57/128"),

resource.TestCheckResourceAttr(name, "endpoints.0.doh.0.enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.doh.0.authentication_enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.doh.0.networks.0.network", "2.5.6.202/32"),
resource.TestCheckResourceAttr(name, "endpoints.0.doh.0.networks.1.network", "3.5.6.203/32"),

resource.TestCheckResourceAttr(name, "endpoints.0.dot.0.enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.dot.0.authentication_enabled", "true"),
resource.TestCheckResourceAttr(name, "endpoints.0.dot.0.networks.0.network", "2.5.6.201/32"),
),
},
},
Expand All @@ -48,6 +66,27 @@ func testAccCloudflareTeamsLocationConfigBasic(rnd, accountID string) string {
resource "cloudflare_zero_trust_dns_location" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
networks = [{ network = "2.5.6.200/32" }]
dns_destination_ips_id = "0e4a32c6-6fb8-4858-9296-98f51631e8e6"
endpoints {
ipv4 {
enabled = true
}
ipv6 {
enabled = true
networks = [ { network = "2a09:bac5:50c3:400::6b:57/128" } ]
}
dot {
enabled = true
networks = [ { network = "2.5.6.201/32" } ]
}
doh {
enabled = true
networks = [ { network = "2.5.6.202/32" }, { network = "3.5.6.203/32" } ]
}
}
}
`, rnd, accountID)
}
Expand Down
Loading

0 comments on commit 132d89b

Please sign in to comment.