Skip to content

Commit

Permalink
Merge pull request #1902 from mlhnono68/feat-accounts-resource
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobbednarz authored Sep 21, 2022
2 parents 461ef3c + 4ebc365 commit 7b496a8
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 12 deletions.
3 changes: 3 additions & 0 deletions .changelog/1902.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
cloudflare_account
```
4 changes: 2 additions & 2 deletions docs/resources/access_rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ resource "cloudflare_access_rule" "office_network" {

### Optional

- `account_id` (String) The account identifier to target for the resource. Must provide only one of `account_id`, `zone_id`.
- `account_id` (String) The account identifier to target for the resource.
- `notes` (String) A personal note about the rule. Typically used as a reminder or explanation for the rule.
- `zone_id` (String) The zone identifier to target for the resource. Must provide only one of `account_id`, `zone_id`.
- `zone_id` (String) The zone identifier to target for the resource.

### Read-Only

Expand Down
44 changes: 44 additions & 0 deletions docs/resources/account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
page_title: "cloudflare_account Resource - Cloudflare"
subcategory: ""
description: |-
Provides a Cloudflare Account resource. Account is the basic resource for
working with Cloudflare zones, teams and users.
---

# cloudflare_account (Resource)

Provides a Cloudflare Account resource. Account is the basic resource for
working with Cloudflare zones, teams and users.

## Example Usage

```terraform
resource "cloudflare_account" "example" {
name = "some-enterprise-account"
type = "enterprise"
enforce_twofactor = true
}
```
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) The name of the account that is displayed in the Cloudflare dashboard.

### Optional

- `enforce_twofactor` (Boolean) Whether 2FA is enforced on the account. Defaults to `false`.
- `type` (String) Account type. Available values: `enterprise`, `standard`. Defaults to `standard`.

### Read-Only

- `id` (String) The ID of this resource.

## Import

Import is supported using the following syntax:
```shell
$ terraform import cloudflare_account.example <account_id>
```
12 changes: 6 additions & 6 deletions docs/resources/email_routing_catch_all.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
---
page_title: "cloudflare_email_routing_rule_catch_all Resource - Cloudflare"
page_title: "cloudflare_email_routing_catch_all Resource - Cloudflare"
subcategory: ""
description: |-
Provides a resource for managing Email Routing Addresses catch all behaviour.
---

# cloudflare_email_routing_rule_catch_all (Resource)
# cloudflare_email_routing_catch_all (Resource)

Provides a resource for managing Email Routing Addresses catch all behaviour.

## Example Usage

```terraform
resource "cloudflare_email_routing_rule_catch_all" "main" {
resource "cloudflare_email_routing_catch_all" "example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "terraform rule"
name = "example catch all"
enabled = true
matcher {
Expand All @@ -27,8 +27,6 @@ resource "cloudflare_email_routing_rule_catch_all" "main" {
}
}
```


<!-- schema generated by tfplugindocs -->
## Schema

Expand Down Expand Up @@ -69,3 +67,5 @@ Optional:

- `field` (String) Field for type matcher.
- `value` (String) Value for matcher.


2 changes: 2 additions & 0 deletions docs/resources/email_routing_rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ Optional:

- `field` (String) Field for type matcher.
- `value` (String) Value for matcher.


1 change: 1 addition & 0 deletions examples/resources/cloudflare_account/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$ terraform import cloudflare_account.example <account_id>
5 changes: 5 additions & 0 deletions examples/resources/cloudflare_account/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource "cloudflare_account" "example" {
name = "some-enterprise-account"
type = "enterprise"
enforce_twofactor = true
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
resource "cloudflare_email_routing_rule_catch_all" "main" {
resource "cloudflare_email_routing_catch_all" "example" {
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
name = "terraform rule"
name = "example catch all"
enabled = true

matcher {
Expand Down
3 changes: 2 additions & 1 deletion internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func New(version string) func() *schema.Provider {
"cloudflare_access_rule": resourceCloudflareAccessRule(),
"cloudflare_access_service_token": resourceCloudflareAccessServiceToken(),
"cloudflare_account_member": resourceCloudflareAccountMember(),
"cloudflare_account": resourceCloudflareAccount(),
"cloudflare_api_shield": resourceCloudflareAPIShield(),
"cloudflare_api_token": resourceCloudflareApiToken(),
"cloudflare_argo_tunnel": resourceCloudflareArgoTunnel(),
Expand Down Expand Up @@ -255,13 +256,13 @@ func New(version string) func() *schema.Provider {
"cloudflare_tunnel_route": resourceCloudflareTunnelRoute(),
"cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(),
"cloudflare_user_agent_blocking_rule": resourceCloudflareUserAgentBlockingRules(),
"cloudflare_web3_hostname": resourceCloudflareWeb3Hostname(),
"cloudflare_waf_group": resourceCloudflareWAFGroup(),
"cloudflare_waf_override": resourceCloudflareWAFOverride(),
"cloudflare_waf_package": resourceCloudflareWAFPackage(),
"cloudflare_waf_rule": resourceCloudflareWAFRule(),
"cloudflare_waiting_room_event": resourceCloudflareWaitingRoomEvent(),
"cloudflare_waiting_room": resourceCloudflareWaitingRoom(),
"cloudflare_web3_hostname": resourceCloudflareWeb3Hostname(),
"cloudflare_worker_cron_trigger": resourceCloudflareWorkerCronTrigger(),
"cloudflare_worker_route": resourceCloudflareWorkerRoute(),
"cloudflare_worker_script": resourceCloudflareWorkerScript(),
Expand Down
120 changes: 120 additions & 0 deletions internal/provider/resource_cloudflare_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package provider

import (
"context"
"errors"
"fmt"

"github.com/MakeNowJust/heredoc/v2"
cloudflare "github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
accountTypeStandard = "standard"
accountTypeEnterprise = "enterprise"
)

func resourceCloudflareAccount() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareAccountSchema(),
CreateContext: resourceCloudflareAccountCreate,
ReadContext: resourceCloudflareAccountRead,
UpdateContext: resourceCloudflareAccountUpdate,
DeleteContext: resourceCloudflareAccountDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Description: heredoc.Doc(`
Provides a Cloudflare Account resource. Account is the basic resource for
working with Cloudflare zones, teams and users.
`),
}
}

func resourceCloudflareAccountCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
accountName := d.Get("name").(string)
accountType := d.Get("type").(string)

tflog.Debug(ctx, fmt.Sprintf("Creating Cloudflare Account: name %s", accountName))

account := cloudflare.Account{
Name: accountName,
Type: accountType,
}
acc, err := client.CreateAccount(ctx, account)

if err != nil {
return diag.FromErr(fmt.Errorf("error creating account %q: %w", accountName, err))
}

d.SetId(acc.ID)

return resourceCloudflareAccountRead(ctx, d, meta)
}

func resourceCloudflareAccountRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
accountID := d.Id()

foundAcc, _, err := client.Account(ctx, accountID)
if err != nil {
var notFoundError *cloudflare.NotFoundError
if errors.As(err, &notFoundError) {
tflog.Info(ctx, fmt.Sprintf("Account %s no longer exists", d.Id()))
d.SetId("")
return nil
}
return diag.FromErr(fmt.Errorf("error finding Account %q: %w", d.Id(), err))
}

tflog.Debug(ctx, fmt.Sprintf("AccountDetails: %#v", foundAcc))

d.Set("name", foundAcc.Name)
d.Set("type", foundAcc.Type)
d.Set("enforce_twofactor", foundAcc.Settings.EnforceTwoFactor)

return nil
}

func resourceCloudflareAccountUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
accountID := d.Id()

tflog.Debug(ctx, fmt.Sprintf("Updating Cloudflare Account: id %s", accountID))

updatedAcc := cloudflare.Account{}
if accountName, ok := d.GetOk("name"); ok {
updatedAcc.Name = accountName.(string)
}

if enforce_twofactor, ok := d.GetOk("enforce_twofactor"); ok {
updatedAcc.Settings.EnforceTwoFactor = enforce_twofactor.(bool)
}

_, err := client.UpdateAccount(ctx, accountID, updatedAcc)
if err != nil {
tflog.Error(ctx, fmt.Sprintf("%#v", err))
return diag.FromErr(fmt.Errorf("error updating Account %q: %w", d.Id(), err))
}

return resourceCloudflareAccountRead(ctx, d, meta)
}

func resourceCloudflareAccountDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
accountID := d.Id()

tflog.Debug(ctx, fmt.Sprintf("Deleting Cloudflare Account: id %s", accountID))

err := client.DeleteAccount(ctx, accountID)

if err != nil {
return diag.FromErr(fmt.Errorf("error deleting Cloudflare Account: %w", err))
}

return nil
}
2 changes: 1 addition & 1 deletion internal/provider/resource_cloudflare_account_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func resourceCloudflareAccountMemberRead(ctx context.Context, d *schema.Resource
func resourceCloudflareAccountMemberDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)

tflog.Info(ctx, fmt.Sprintf("Deleting Cloudflare account member ID: %s", d.Id()))
tflog.Debug(ctx, fmt.Sprintf("Deleting Cloudflare account member ID: %s", d.Id()))

var accountID string
if d.Get("account_id").(string) != "" {
Expand Down
45 changes: 45 additions & 0 deletions internal/provider/resource_cloudflare_account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package provider

import (
"fmt"
"testing"

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

func TestAccCloudflareAccount_Basic(t *testing.T) {
t.Parallel()

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

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareAccountName(fmt.Sprintf("%s_old", rnd)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
name, "name", fmt.Sprintf("%s_old", rnd)),
),
},
{
Config: testAccCheckCloudflareAccountName(fmt.Sprintf("%s_new", rnd)),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
name, "name", fmt.Sprintf("%s_new", rnd)),
),
},
},
})
}

func testAccCheckCloudflareAccountName(name string) string {
return fmt.Sprintf(`
resource "cloudflare_account" "%[1]s" {
name = "%[1]s"
}`, name)
}
32 changes: 32 additions & 0 deletions internal/provider/schema_cloudflare_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package provider

import (
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceCloudflareAccountSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the account that is displayed in the Cloudflare dashboard.",
},
"type": {
Type: schema.TypeString,
Optional: true,
Description: fmt.Sprintf("Account type. %s", renderAvailableDocumentationValuesStringSlice([]string{accountTypeEnterprise, accountTypeStandard})),
Default: accountTypeStandard,
ValidateFunc: validation.StringInSlice([]string{accountTypeEnterprise, accountTypeStandard}, false),
ForceNew: true, // "Updating account type is not supported from client api"
},
"enforce_twofactor": {
Description: "Whether 2FA is enforced on the account.",
Type: schema.TypeBool,
Default: false,
Optional: true,
},
}
}

0 comments on commit 7b496a8

Please sign in to comment.