Skip to content

Commit

Permalink
GATE-1848: Adds support for gateway account config api
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Borkenstein committed Aug 31, 2021
1 parent 6cbde52 commit d633db0
Show file tree
Hide file tree
Showing 3 changed files with 308 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 @@ -146,6 +146,7 @@ func Provider() terraform.ResourceProvider {
"cloudflare_static_route": resourceCloudflareStaticRoute(),
"cloudflare_teams_list": resourceCloudflareTeamsList(),
"cloudflare_teams_location": resourceCloudflareTeamsLocation(),
"cloudflare_teams_account": resourceCloudflareTeamsAccountConfiguration(),
"cloudflare_waf_group": resourceCloudflareWAFGroup(),
"cloudflare_waf_package": resourceCloudflareWAFPackage(),
"cloudflare_waf_rule": resourceCloudflareWAFRule(),
Expand Down
237 changes: 237 additions & 0 deletions cloudflare/resource_cloudflare_teams_accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
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 resourceCloudflareTeamsAccountConfiguration() *schema.Resource {
return &schema.Resource{
Read: resourceCloudflareTeamsAccountConfigurationRead,
Update: resourceCloudflareTeamsAccountConfigurationUpdate,
Create: resourceCloudflareTeamsAccountConfigurationUpdate,
// This resource is a top-level account configuration and cant be "deleted"
Delete: func(_ *schema.ResourceData, _ interface{}) error { return nil },
Importer: &schema.ResourceImporter{
State: resourceCloudflareTeamsAccountImport,
},

Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Required: true,
},
"block_page": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: blockPageSchema,
},
},
"antivirus": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: antivirusSchema,
},
},
"tls_decrypt_enabled": {
Type: schema.TypeBool,
Optional: true,
},
"activity_log_enabled": {
Type: schema.TypeBool,
Optional: true,
},
},
}
}

var blockPageSchema = map[string]*schema.Schema{
"enabled": {
Type: schema.TypeBool,
Optional: true,
},
"footer_text": {
Type: schema.TypeString,
Optional: true,
},
"header_text": {
Type: schema.TypeString,
Optional: true,
},
"logo_path": {
Type: schema.TypeString,
Optional: true,
},
"background_color": {
Type: schema.TypeString,
Optional: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
},
}

var antivirusSchema = map[string]*schema.Schema{
"enabled_download_phase": {
Type: schema.TypeBool,
Required: true,
},
"enabled_upload_phase": {
Type: schema.TypeBool,
Required: true,
},
"fail_closed": {
Type: schema.TypeBool,
Required: true,
},
}

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

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

if configuration.Settings.BlockPage != nil {
if err := d.Set("block_page", flattenBlockPageConfig(configuration.Settings.BlockPage)); err != nil {
return errors.Wrap(err, "error parsing account block page config")
}
}

if configuration.Settings.Antivirus != nil {
if err := d.Set("antivirus", flattenAntivirusConfig(configuration.Settings.Antivirus)); err != nil {
return errors.Wrap(err, "error parsing account antivirus config")
}
}

if configuration.Settings.TLSDecrypt != nil {
if err := d.Set("tls_decrypt_enabled", configuration.Settings.TLSDecrypt.Enabled); err != nil {
return errors.Wrap(err, "error parsing account tls decrypt enablement")
}
}

if configuration.Settings.ActivityLog != nil {
if err := d.Set("activity_log_enabled", configuration.Settings.ActivityLog.Enabled); err != nil {
return errors.Wrap(err, "error parsing account activity log enablement")
}
}
return nil
}

func resourceCloudflareTeamsAccountConfigurationUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)
blockPageConfig := inflateBlockPageConfig(d.Get("block_page"))
antivirusConfig := inflateAntivirusConfig(d.Get("antivirus"))
updatedTeamsAccount := cloudflare.TeamsConfiguration{
Settings: cloudflare.TeamsAccountSettings{
Antivirus: antivirusConfig,
BlockPage: blockPageConfig,
},
}

tlsDecrypt, ok := d.GetOkExists("tls_decrypt_enabled")
if ok {
updatedTeamsAccount.Settings.TLSDecrypt = &cloudflare.TeamsTLSDecrypt{Enabled: tlsDecrypt.(bool)}
}

activtyLog, ok := d.GetOkExists("activity_log_enabled")
if ok {
updatedTeamsAccount.Settings.ActivityLog = &cloudflare.TeamsActivityLog{Enabled: activtyLog.(bool)}
}
log.Printf("[DEBUG] Updating Cloudflare Teams Account configuration from struct: %+v", updatedTeamsAccount)

if _, err := client.TeamsAccountUpdateConfiguration(context.Background(), accountID, updatedTeamsAccount); err != nil {
return fmt.Errorf("error updating Teams Account configuration for account %q: %s", accountID, err)
}

d.SetId(accountID)
return resourceCloudflareTeamsAccountConfigurationRead(d, meta)
}

func resourceCloudflareTeamsAccountImport(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/teamsAccountID\"", d.Id())
}

accountID := attributes[0]
log.Printf("[DEBUG] Importing Cloudflare Teams Account configuration for account %s", accountID)

d.Set("account_id", accountID)
err := resourceCloudflareTeamsAccountConfigurationRead(d, meta)
return []*schema.ResourceData{d}, err
}

func flattenBlockPageConfig(blockPage *cloudflare.TeamsBlockPage) []interface{} {
return []interface{}{map[string]interface{}{
"enabled": *blockPage.Enabled,
"footer_text": blockPage.FooterText,
"header_text": blockPage.HeaderText,
"logo_path": blockPage.LogoPath,
"background_color": blockPage.BackgroundColor,
"name": blockPage.Name,
}}
}

func inflateBlockPageConfig(blockPage interface{}) *cloudflare.TeamsBlockPage {
blockPageList := blockPage.([]interface{})
if len(blockPageList) != 1 {
return nil
}

blockPageMap := blockPageList[0].(map[string]interface{})
enabled := blockPageMap["enabled"].(bool)
return &cloudflare.TeamsBlockPage{
Enabled: &enabled,
FooterText: blockPageMap["footer_text"].(string),
HeaderText: blockPageMap["header_text"].(string),
LogoPath: blockPageMap["logo_path"].(string),
BackgroundColor: blockPageMap["background_color"].(string),
Name: blockPageMap["name"].(string),
}

}

func flattenAntivirusConfig(antivirusConfig *cloudflare.TeamsAntivirus) []interface{} {
return []interface{}{map[string]interface{}{
"enabled_download_phase": antivirusConfig.EnabledDownloadPhase,
"enabled_upload_phase": antivirusConfig.EnabledUploadPhase,
"fail_closed": antivirusConfig.FailClosed,
}}
}

func inflateAntivirusConfig(antivirus interface{}) *cloudflare.TeamsAntivirus {
avList := antivirus.([]interface{})

if len(avList) != 1 {
return nil
}

avMap := avList[0].(map[string]interface{})
return &cloudflare.TeamsAntivirus{
EnabledDownloadPhase: avMap["enabled_download_phase"].(bool),
EnabledUploadPhase: avMap["enabled_upload_phase"].(bool),
FailClosed: avMap["fail_closed"].(bool),
}
}
70 changes: 70 additions & 0 deletions cloudflare/resource_cloudflare_teams_accounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package cloudflare

import (
"fmt"
"os"
"testing"

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

func TestAccCloudflareTeamsAccountConfigurationBasic(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Access
// service does not yet support the API tokens and it results in
// misleading state error messages.
if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
defer func(apiToken string) {
os.Setenv("CLOUDFLARE_API_TOKEN", apiToken)
}(os.Getenv("CLOUDFLARE_API_TOKEN"))
os.Setenv("CLOUDFLARE_API_TOKEN", "")
}

rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_teams_account.%s", rnd)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccessAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCloudflareTeamsAccountConfigBasic(rnd, accountID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "account_id", accountID),
resource.TestCheckResourceAttr(name, "tls_decrypt_enabled", "true"),
resource.TestCheckResourceAttr(name, "activity_log_enabled", "true"),
resource.TestCheckResourceAttr(name, "block_page.0.name", rnd),
resource.TestCheckResourceAttr(name, "block_page.0.enabled", "true"),
resource.TestCheckResourceAttr(name, "block_page.0.footer_text", "hello"),
resource.TestCheckResourceAttr(name, "block_page.0.header_text", "hello"),
resource.TestCheckResourceAttr(name, "block_page.0.background_color", "#000000"),
resource.TestCheckResourceAttr(name, "block_page.0.logo_path", "https://google.com"),
),
},
},
})
}

func testAccCloudflareTeamsAccountConfigBasic(rnd, accountID string) string {
return fmt.Sprintf(`
resource "cloudflare_teams_account" "%[1]s" {
account_id = "%[2]s"
tls_decrypt_enabled = true
activity_log_enabled = true
block_page {
name="%[1]s"
enabled=true
footer_text="hello"
header_text="hello"
logo_path="https://google.com"
background_color="#000000"
}
antivirus {
enabled_download_phase = true
enabled_upload_phase = false
fail_closed = true
}
}
`, rnd, accountID)
}

0 comments on commit d633db0

Please sign in to comment.