Skip to content

Commit

Permalink
GATE-1848: Adds support for gateway location API
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Borkenstein authored and jacobbednarz committed Aug 26, 2021
1 parent c14c5ca commit 6a65612
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 0 deletions.
1 change: 1 addition & 0 deletions cloudflare/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func Provider() terraform.ResourceProvider {
"cloudflare_spectrum_application": resourceCloudflareSpectrumApplication(),
"cloudflare_static_route": resourceCloudflareStaticRoute(),
"cloudflare_teams_list": resourceCloudflareTeamsList(),
"cloudflare_teams_location": resourceCloudflareTeamsLocation(),
"cloudflare_waf_group": resourceCloudflareWAFGroup(),
"cloudflare_waf_package": resourceCloudflareWAFPackage(),
"cloudflare_waf_rule": resourceCloudflareWAFRule(),
Expand Down
235 changes: 235 additions & 0 deletions cloudflare/resource_cloudflare_teams_location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package cloudflare

import (
"context"
"fmt"
"log"
"strings"

"github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/pkg/errors"
)

func resourceCloudflareTeamsLocation() *schema.Resource {
return &schema.Resource{
Create: resourceCloudflareTeamsLocationCreate,
Read: resourceCloudflareTeamsLocationRead,
Update: resourceCloudflareTeamsLocationUpdate,
Delete: resourceCloudflareTeamsLocationDelete,
Importer: &schema.ResourceImporter{
State: resourceCloudflareTeamsLocationImport,
},

Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Required: true,
},
"name": {
Type: schema.TypeString,
Required: true,
},
"networks": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"network": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"client_default": {
Type: schema.TypeBool,
Optional: true,
},
"policy_ids": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
},
"ip": {
Type: schema.TypeString,
Computed: true,
},
"doh_subdomain": {
Type: schema.TypeString,
Computed: true,
},
"anonymized_logs_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"ipv4_destination": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceCloudflareTeamsLocationRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)

location, err := client.TeamsLocation(context.Background(), accountID, d.Id())
if err != nil {
if strings.Contains(err.Error(), "HTTP status 400") {
log.Printf("[INFO] Teams Location %s no longer exists", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("error finding Teams Location %q: %s", d.Id(), err)
}

if err := d.Set("name", location.Name); err != nil {
return fmt.Errorf("error parsing Location name")
}
if err := d.Set("networks", flattenTeamsLocationNetworks(location.Networks)); err != nil {
return fmt.Errorf("error parsing Location networks")
}
if err := d.Set("policy_ids", location.PolicyIDs); err != nil {
return fmt.Errorf("error parsing Location policy IDs")
}
if err := d.Set("ip", location.Ip); err != nil {
return fmt.Errorf("error parsing Location IP")
}
if err := d.Set("doh_subdomain", location.Subdomain); err != nil {
return fmt.Errorf("error parsing Location DOH subdomain")
}
if err := d.Set("anonymized_logs_enabled", location.AnonymizedLogsEnabled); err != nil {
return fmt.Errorf("error parsing Location anonimized log enablement")
}
if err := d.Set("ipv4_destination", location.IPv4Destination); err != nil {
return fmt.Errorf("error parsing Location IPv4 destination")
}
if err := d.Set("client_default", location.ClientDefault); err != nil {
return fmt.Errorf("error parsing Location client default")
}

return nil
}
func resourceCloudflareTeamsLocationCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)

accountID := d.Get("account_id").(string)
networks, err := inflateTeamsLocationNetworks(d.Get("networks"))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error creating Teams Location for account %q: %s, %v", accountID, err, networks))
}

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

log.Printf("[DEBUG] Creating Cloudflare Teams Location from struct: %+v", newTeamLocation)

location, err := client.CreateTeamsLocation(context.Background(), accountID, newTeamLocation)
if err != nil {
return fmt.Errorf("error creating Teams Location for account %q: %s, %v", accountID, err, networks)
}

d.SetId(location.ID)
return resourceCloudflareTeamsLocationRead(d, meta)

}
func resourceCloudflareTeamsLocationUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)
networks, err := inflateTeamsLocationNetworks(d.Get("networks"))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("error updating Teams Location for account %q: %s, %v", accountID, err, networks))
}
updatedTeamsLocation := cloudflare.TeamsLocation{
ID: d.Id(),
Name: d.Get("name").(string),
ClientDefault: d.Get("client_default").(bool),
Networks: networks,
}
log.Printf("[DEBUG] Updating Cloudflare Teams Location from struct: %+v", updatedTeamsLocation)

teamsLocation, err := client.UpdateTeamsLocation(context.Background(), accountID, updatedTeamsLocation)
if err != nil {
return fmt.Errorf("error updating Teams Location for account %q: %s", accountID, err)
}
if teamsLocation.ID == "" {
return fmt.Errorf("failed to find Teams Location ID in update response; resource was empty")
}
return resourceCloudflareTeamsLocationRead(d, meta)
}

func resourceCloudflareTeamsLocationDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
id := d.Id()
accountID := d.Get("account_id").(string)

log.Printf("[DEBUG] Deleting Cloudflare Teams Location using ID: %s", id)

err := client.DeleteTeamsLocation(context.Background(), accountID, id)
if err != nil {
return fmt.Errorf("error deleting Teams Location for account %q: %s", accountID, err)
}

return resourceCloudflareTeamsLocationRead(d, meta)
}

func resourceCloudflareTeamsLocationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
attributes := strings.SplitN(d.Id(), "/", 2)

if len(attributes) != 2 {
return nil, fmt.Errorf("invalid id (\"%s\") specified, should be in format \"accountID/teamsLocationID\"", d.Id())
}

accountID, teamsLocationID := attributes[0], attributes[1]

log.Printf("[DEBUG] Importing Cloudflare Teams Location: id %s for account %s", teamsLocationID, accountID)

d.Set("account_id", accountID)
d.SetId(teamsLocationID)

err := resourceCloudflareTeamsLocationRead(d, meta)

return []*schema.ResourceData{d}, err

}

func inflateTeamsLocationNetworks(networks interface{}) ([]cloudflare.TeamsLocationNetwork, error) {
var networkStructs []cloudflare.TeamsLocationNetwork
if networks != nil {
networkSet, ok := networks.(*schema.Set)
if !ok {
return nil, fmt.Errorf("error parsing network list")
}
for _, i := range networkSet.List() {
network, ok := i.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("error parsing network")
}
networkStructs = append(networkStructs, cloudflare.TeamsLocationNetwork{
ID: network["id"].(string),
Network: network["network"].(string),
})
}
}
return networkStructs, 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
}
60 changes: 60 additions & 0 deletions cloudflare/resource_cloudflare_teams_location_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cloudflare

import (
"context"
"fmt"
"testing"

"github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func TestAccCloudflareTeamsLocationBasic(t *testing.T) {
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_teams_location.%s", rnd)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccessAccPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudflareTeamsLocationDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudflareTeamsLocationConfigBasic(rnd, accountID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "account_id", accountID),
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "client_default", "false"),
),
},
},
})
}

func testAccCloudflareTeamsLocationConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
resource "cloudflare_teams_location" "%[1]s" {
name = "%[1]s"
account_id = "%[2]s"
}
`, rnd, accountID)
}

func testAccCheckCloudflareTeamsLocationDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*cloudflare.API)

for _, rs := range s.RootModule().Resources {
if rs.Type != "cloudflare_teams_location" {
continue
}

_, err := client.TeamsLocation(context.Background(), rs.Primary.Attributes["account_id"], rs.Primary.ID)
if err == nil {
return fmt.Errorf("teams Location still exists")
}
}

return nil
}

0 comments on commit 6a65612

Please sign in to comment.