diff --git a/.changelog/2866.txt b/.changelog/2866.txt new file mode 100644 index 0000000000..27c9ceb8e0 --- /dev/null +++ b/.changelog/2866.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +cloudflare_tunnel +``` diff --git a/docs/data-sources/tunnel.md b/docs/data-sources/tunnel.md new file mode 100644 index 0000000000..3f3f02e292 --- /dev/null +++ b/docs/data-sources/tunnel.md @@ -0,0 +1,36 @@ +--- +page_title: "cloudflare_tunnel Data Source - Cloudflare" +subcategory: "" +description: |- + Use this datasource to lookup a tunnel in an account. +--- + +# cloudflare_tunnel (Data Source) + +Use this datasource to lookup a tunnel in an account. + +## Example Usage + +```terraform +data "cloudflare_tunnel" "example" { + account_id = "f037e56e89293a057740de681ac9abbe" + name = "my-tunnel" +} +``` + + +## Schema + +### Required + +- `account_id` (String) The account identifier to target for the resource. **Modifying this attribute will force creation of a new resource.** +- `name` (String) Name of the tunnel. **Modifying this attribute will force creation of a new resource.** + +### Read-Only + +- `id` (String) ID of the tunnel. +- `remote_config` (Boolean) Whether the tunnel can be configured remotely from the Zero Trust dashboard. +- `status` (String) The status of the tunnel. Available values: `inactive`, `degraded`, `healthy`, `down`. +- `tunnel_type` (String) The type of the tunnel. Available values: `cfd_tunnel`, `warp_connector`. + + diff --git a/examples/data-sources/cloudflare_tunnel/data-source.tf b/examples/data-sources/cloudflare_tunnel/data-source.tf new file mode 100644 index 0000000000..68174e7b0f --- /dev/null +++ b/examples/data-sources/cloudflare_tunnel/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_tunnel" "example" { + account_id = "f037e56e89293a057740de681ac9abbe" + name = "my-tunnel" +} diff --git a/internal/sdkv2provider/data_source_tunnel.go b/internal/sdkv2provider/data_source_tunnel.go new file mode 100644 index 0000000000..19541d31a0 --- /dev/null +++ b/internal/sdkv2provider/data_source_tunnel.go @@ -0,0 +1,78 @@ +package sdkv2provider + +import ( + "context" + "fmt" + + "github.com/cloudflare/cloudflare-go" + "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceCloudflareTunnel() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceCloudflareTunnelRead, + + Schema: map[string]*schema.Schema{ + consts.AccountIDSchemaKey: { + Description: consts.AccountIDSchemaDescription, + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the tunnel.", + ForceNew: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the tunnel.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: fmt.Sprintf("The status of the tunnel. %s", renderAvailableDocumentationValuesStringSlice([]string{"inactive", "degraded", "healthy", "down"})), + }, + "tunnel_type": { + Type: schema.TypeString, + Computed: true, + Description: fmt.Sprintf("The type of the tunnel. %s", renderAvailableDocumentationValuesStringSlice([]string{"cfd_tunnel", "warp_connector"})), + }, + "remote_config": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether the tunnel can be configured remotely from the Zero Trust dashboard.", + }, + }, + Description: "Use this datasource to lookup a tunnel in an account.", + } +} + +func dataSourceCloudflareTunnelRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + tflog.Debug(ctx, "Reading Tunnel") + client := meta.(*cloudflare.API) + accID := d.Get(consts.AccountIDSchemaKey).(string) + + name := d.Get("name").(string) + tunnels, _, err := client.ListTunnels(ctx, cloudflare.AccountIdentifier(accID), cloudflare.TunnelListParams{Name: name}) + if err != nil { + return diag.FromErr(fmt.Errorf("failed to fetch Tunnel: %w", err)) + } + if len(tunnels) == 0 { + return diag.FromErr(fmt.Errorf("No tunnels with name: %s", name)) + } + + tunnel := tunnels[0] + + d.SetId(tunnel.ID) + d.Set("status", tunnel.Status) + d.Set("id", tunnel.ID) + d.Set("tunnel_type", tunnel.TunnelType) + d.Set("remote_config", tunnel.RemoteConfig) + return nil +} diff --git a/internal/sdkv2provider/data_source_tunnel_test.go b/internal/sdkv2provider/data_source_tunnel_test.go new file mode 100644 index 0000000000..abed79c218 --- /dev/null +++ b/internal/sdkv2provider/data_source_tunnel_test.go @@ -0,0 +1,43 @@ +package sdkv2provider + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccCloudflareTunnel_MatchName(t *testing.T) { + rnd := generateRandomResourceName() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testCloudflareTunnelMatchName(rnd), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.cloudflare_tunnel."+rnd, "status", "inactive"), + ), + }, + }, + }) +} + +func testCloudflareTunnelMatchName(name string) string { + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + return fmt.Sprintf(` +resource "cloudflare_tunnel" "%[2]s" { + account_id = "%[1]s" + name = "%[2]s" + secret = "AQIDBAUGBwgBAgMEBQYHCAECAwQFBgcIAQIDBAUGBwg=" +} + +data "cloudflare_tunnel" "%[2]s" { + account_id = cloudflare_tunnel.%[2]s.account_id + name = cloudflare_tunnel.%[2]s.name + depends_on = [cloudflare_tunnel.%[2]s] +} +`, accountID, name) +} diff --git a/internal/sdkv2provider/provider.go b/internal/sdkv2provider/provider.go index 19023f57bd..ab4fd08ff0 100644 --- a/internal/sdkv2provider/provider.go +++ b/internal/sdkv2provider/provider.go @@ -172,6 +172,7 @@ func New(version string) func() *schema.Provider { "cloudflare_record": dataSourceCloudflareRecord(), "cloudflare_rulesets": dataSourceCloudflareRulesets(), "cloudflare_zone_cache_reserve": dataSourceCloudflareZoneCacheReserve(), + "cloudflare_tunnel": dataSourceCloudflareTunnel(), "cloudflare_zone_dnssec": dataSourceCloudflareZoneDNSSEC(), "cloudflare_zone": dataSourceCloudflareZone(), "cloudflare_zones": dataSourceCloudflareZones(),