Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for account resource #1902

Merged
merged 23 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d756a2b
functional cloudflare_account resource
mlhnono68 Sep 9, 2022
4b34348
adding basic test for cloudflare_account resource
mlhnono68 Sep 9, 2022
82ef4cd
adding changelog
mlhnono68 Sep 9, 2022
e0e4273
verifying UpdateAccount return value
mlhnono68 Sep 9, 2022
26f36dc
Update internal/provider/resource_cloudflare_account.go
mlhnono68 Sep 14, 2022
50c8a98
validate account type by schema validation only
mlhnono68 Sep 14, 2022
9f6a575
removing redundant getCloudflareAccontFromId
mlhnono68 Sep 14, 2022
4778e72
cleaning useless error debug finding accountID
mlhnono68 Sep 14, 2022
eb17af3
replacing GetOkExists by GetOk for account properties
mlhnono68 Sep 14, 2022
3dc566a
adding support for error 1001 to be ignored
mlhnono68 Sep 14, 2022
69d4f39
tflog instead of printf
mlhnono68 Sep 14, 2022
f628d5a
simpler if
mlhnono68 Sep 14, 2022
9cfa418
adding example
mlhnono68 Sep 14, 2022
15dc2c5
after make docs
mlhnono68 Sep 14, 2022
732a819
additional account.md
mlhnono68 Sep 14, 2022
b8011c7
using errors.As
mlhnono68 Sep 14, 2022
bdaf421
omitting Account.Type on update to prevent 1001 error
mlhnono68 Sep 15, 2022
3c48170
Merge branch 'master' into feat-accounts-resource
jacobbednarz Sep 21, 2022
1632568
clean up examples
jacobbednarz Sep 21, 2022
879670f
fix test cases and building updated accounts
jacobbednarz Sep 21, 2022
d321272
sort resources alphabetically
jacobbednarz Sep 21, 2022
6359a83
fix schema definition
jacobbednarz Sep 21, 2022
4ebc365
fix `email_routing_catch_all docs`
jacobbednarz Sep 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
jacobbednarz marked this conversation as resolved.
Show resolved Hide resolved

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,
},
}
}