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

Added optional config_src parameter to cloudflare_tunnel resource #2369

Merged
merged 3 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/2369.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_tunnel: Adds config_src parameter
```
4 changes: 4 additions & 0 deletions docs/resources/tunnel.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ resource "cloudflare_tunnel" "example" {
- `name` (String) A user-friendly name chosen when the tunnel is created. **Modifying this attribute will force creation of a new resource.**
- `secret` (String, Sensitive) 32 or more bytes, encoded as a base64 string. The Create Argo Tunnel endpoint sets this as the tunnel's password. Anyone wishing to run the tunnel needs this password. **Modifying this attribute will force creation of a new resource.**

### Optional

- `config_src` (String) Indicates if this is a locally or remotely configured tunnel. If `local`, manage the tunnel using a YAML file on the origin machine. If `cloudflare`, manage the tunnel on the Zero Trust dashboard or using tunnel_config, tunnel_route or tunnel_virtual_network resources. Available values: `local`, `cloudflare`. **Modifying this attribute will force creation of a new resource.**

### Read-Only

- `cname` (String) Usable CNAME for accessing the Tunnel.
Expand Down
11 changes: 10 additions & 1 deletion internal/sdkv2provider/resource_cloudflare_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ func resourceCloudflareTunnelCreate(ctx context.Context, d *schema.ResourceData,
accID := d.Get(consts.AccountIDSchemaKey).(string)
name := d.Get("name").(string)
secret := d.Get("secret").(string)
configSrc := d.Get("config_src").(string)

tunnel, err := client.CreateTunnel(ctx, cloudflare.AccountIdentifier(accID), cloudflare.TunnelCreateParams{Name: name, Secret: secret})
tunnel, err := client.CreateTunnel(ctx, cloudflare.AccountIdentifier(accID), cloudflare.TunnelCreateParams{Name: name, Secret: secret, ConfigSrc: configSrc})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("failed to create Argo Tunnel")))
}
Expand Down Expand Up @@ -69,6 +70,14 @@ func resourceCloudflareTunnelRead(ctx context.Context, d *schema.ResourceData, m
d.Set("cname", fmt.Sprintf("%s.%s", tunnel.ID, argoTunnelCNAME))
d.Set("tunnel_token", token)

if d.Get("config_src").(string) != "" {
if tunnel.RemoteConfig {
d.Set("config_src", "cloudflare")
} else {
d.Set("config_src", "local")
}
}

return nil
}

Expand Down
82 changes: 82 additions & 0 deletions internal/sdkv2provider/resource_cloudflare_tunnel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,88 @@ func testAccCheckCloudflareTunnelBasic(accID, name string) string {
}`, accID, name)
}

func TestAccCloudflareTunnelCreate_Managed(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Argo Tunnel
// endpoint does not yet support the API tokens.
if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
t.Setenv("CLOUDFLARE_API_TOKEN", "")
}

accID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_tunnel.%s", rnd)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckCloudflareTunnelDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareTunnelManaged(accID, rnd),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "secret", "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="),
resource.TestMatchResourceAttr(name, "cname", regexp.MustCompile(".*\\.cfargotunnel\\.com")),
resource.TestCheckResourceAttr(name, "config_src", "cloudflare"),
),
},
},
})
}

func testAccCheckCloudflareTunnelManaged(accID, name string) string {
return fmt.Sprintf(`
resource "cloudflare_tunnel" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
config_src = "cloudflare"
}`, accID, name)
}

func TestAccCloudflareTunnelCreate_Unmanaged(t *testing.T) {
// Temporarily unset CLOUDFLARE_API_TOKEN if it is set as the Argo Tunnel
// endpoint does not yet support the API tokens.
if os.Getenv("CLOUDFLARE_API_TOKEN") != "" {
t.Setenv("CLOUDFLARE_API_TOKEN", "")
}

accID := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
rnd := generateRandomResourceName()
name := fmt.Sprintf("cloudflare_tunnel.%s", rnd)

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: providerFactories,
CheckDestroy: testAccCheckCloudflareTunnelDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckCloudflareTunnelUnmanaged(accID, rnd),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "name", rnd),
resource.TestCheckResourceAttr(name, "secret", "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="),
resource.TestMatchResourceAttr(name, "cname", regexp.MustCompile(".*\\.cfargotunnel\\.com")),
resource.TestCheckResourceAttr(name, "config_src", "local"),
),
},
},
})
}

func testAccCheckCloudflareTunnelUnmanaged(accID, name string) string {
return fmt.Sprintf(`
resource "cloudflare_tunnel" "%[2]s" {
account_id = "%[1]s"
name = "%[2]s"
secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg="
config_src = "local"
}`, accID, name)
}

func testAccCheckCloudflareTunnelDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "cloudflare_tunnel" {
Expand Down
10 changes: 10 additions & 0 deletions internal/sdkv2provider/schema_cloudflare_tunnel.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package sdkv2provider

import (
"fmt"

"github.com/cloudflare/terraform-provider-cloudflare/internal/consts"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceCloudflareTunnelSchema() map[string]*schema.Schema {
Expand All @@ -26,6 +29,13 @@ func resourceCloudflareTunnelSchema() map[string]*schema.Schema {
ForceNew: true,
Description: "32 or more bytes, encoded as a base64 string. The Create Argo Tunnel endpoint sets this as the tunnel's password. Anyone wishing to run the tunnel needs this password.",
},
"config_src": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"local", "cloudflare"}, false),
Description: fmt.Sprintf("Indicates if this is a locally or remotely configured tunnel. If `local`, manage the tunnel using a YAML file on the origin machine. If `cloudflare`, manage the tunnel on the Zero Trust dashboard or using tunnel_config, tunnel_route or tunnel_virtual_network resources. %s", renderAvailableDocumentationValuesStringSlice([]string{"local", "cloudflare"})),
},
"cname": {
Type: schema.TypeString,
Computed: true,
Expand Down