diff --git a/.changelog/1882.txt b/.changelog/1882.txt new file mode 100644 index 0000000000..096a721b1e --- /dev/null +++ b/.changelog/1882.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +cloudflare_web3_hostname +``` diff --git a/docs/resources/access_service_token.md b/docs/resources/access_service_token.md index 143c8bc45b..8d5af11805 100644 --- a/docs/resources/access_service_token.md +++ b/docs/resources/access_service_token.md @@ -44,7 +44,7 @@ resource "cloudflare_access_service_token" "my_app" { ### Optional - `account_id` (String) The account identifier to target for the resource. Conflicts with `zone_id`. -- `min_days_for_renewal` (Number) Regenerates the token if terraform is run within the specified amount of days before expiration. Defaults to `0`. +- `min_days_for_renewal` (Number) Refresh the token if terraform is run within the specified amount of days before expiration. Defaults to `0`. - `zone_id` (String) The zone identifier to target for the resource. Conflicts with `account_id`. ### Read-Only diff --git a/docs/resources/web3_hostname.md b/docs/resources/web3_hostname.md new file mode 100644 index 0000000000..93caf8c1b9 --- /dev/null +++ b/docs/resources/web3_hostname.md @@ -0,0 +1,34 @@ +--- +page_title: "cloudflare_web3_hostname Resource - Cloudflare" +subcategory: "" +description: |- + Manages Web3 hostnames for IPFS and Ethereum gateways. +--- + +# cloudflare_web3_hostname (Resource) + +Manages Web3 hostnames for IPFS and Ethereum gateways. + + + +## Schema + +### Required + +- `name` (String) The hostname that will point to the target gateway via CNAME. +- `target` (String) Target gateway of the hostname. +- `zone_id` (String) The zone identifier to target for the resource. + +### Optional + +- `description` (String) An optional description of the hostname. +- `dnslink` (String) DNSLink value used if the target is ipfs. + +### Read-Only + +- `created_on` (String) Creation time. +- `id` (String) The ID of this resource. +- `modified_on` (String) Last modification time. +- `status` (String) Status of the hostname's activation. + + diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 7bb02a0854..638186c321 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -250,6 +250,7 @@ func New(version string) func() *schema.Provider { "cloudflare_teams_rule": resourceCloudflareTeamsRule(), "cloudflare_tunnel_route": resourceCloudflareTunnelRoute(), "cloudflare_tunnel_virtual_network": resourceCloudflareTunnelVirtualNetwork(), + "cloudflare_web3_hostname": resourceCloudflareWeb3Hostname(), "cloudflare_waf_group": resourceCloudflareWAFGroup(), "cloudflare_waf_override": resourceCloudflareWAFOverride(), "cloudflare_waf_package": resourceCloudflareWAFPackage(), diff --git a/internal/provider/resource_cloudflare_web3hostname.go b/internal/provider/resource_cloudflare_web3hostname.go new file mode 100644 index 0000000000..dcc6f124e5 --- /dev/null +++ b/internal/provider/resource_cloudflare_web3hostname.go @@ -0,0 +1,96 @@ +package provider + +import ( + "context" + "fmt" + + "github.com/MakeNowJust/heredoc/v2" + "github.com/cloudflare/cloudflare-go" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceCloudflareWeb3Hostname() *schema.Resource { + return &schema.Resource{ + Schema: resourceCloudflareWeb3HostnameSchema(), + CreateContext: resourceCloudflareWeb3HostnameCreate, + ReadContext: resourceCloudflareWeb3HostnameRead, + UpdateContext: resourceCloudflareWeb3HostnameUpdate, + DeleteContext: resourceCloudflareWeb3HostnameDelete, + Description: heredoc.Doc(` + Manages Web3 hostnames for IPFS and Ethereum gateways. + `), + } +} + +func resourceCloudflareWeb3HostnameCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + + hostname, err := client.CreateWeb3Hostname(ctx, cloudflare.Web3HostnameCreateParameters{ + ZoneID: d.Get("zone_id").(string), + Name: d.Get("name").(string), + Target: d.Get("target").(string), + Description: d.Get("description").(string), + DNSLink: d.Get("dnslink").(string), + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error creating web3hostname %q: %w", d.Get("name").(string), err)) + } + + d.SetId(hostname.ID) + + return resourceCloudflareWeb3HostnameRead(ctx, d, meta) +} + +func resourceCloudflareWeb3HostnameRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + + hostname, err := client.GetWeb3Hostname(ctx, cloudflare.Web3HostnameDetailsParameters{ + ZoneID: d.Get("zone_id").(string), + Identifier: d.Id(), + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error reading web3hostname %q: %w", d.Id(), err)) + } + + d.SetId(hostname.ID) + + return nil +} + +func resourceCloudflareWeb3HostnameUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + zoneID := d.Get("zone_id").(string) + + hostname, err := client.UpdateWeb3Hostname(ctx, cloudflare.Web3HostnameUpdateParameters{ + ZoneID: zoneID, + Identifier: d.Id(), + Description: d.Get("description").(string), + DNSLink: d.Get("dnslink").(string), + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error updating web3hostname %q: %w", d.Id(), err)) + } + + d.SetId(hostname.ID) + + return resourceCloudflareWeb3HostnameRead(ctx, d, meta) +} + +func resourceCloudflareWeb3HostnameDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*cloudflare.API) + + _, err := client.DeleteWeb3Hostname(ctx, cloudflare.Web3HostnameDetailsParameters{ + ZoneID: d.Get("zone_id").(string), + Identifier: d.Id(), + }) + + if err != nil { + return diag.FromErr(fmt.Errorf("error deleting web3hostname %q: %w", d.Id(), err)) + } + + return nil +} diff --git a/internal/provider/resource_cloudflare_web3hostname_test.go b/internal/provider/resource_cloudflare_web3hostname_test.go new file mode 100644 index 0000000000..86928fb16f --- /dev/null +++ b/internal/provider/resource_cloudflare_web3hostname_test.go @@ -0,0 +1,79 @@ +package provider + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func buildWeb3HostnameConfigEthereum(name, zoneID, domain string) string { + return fmt.Sprintf(` +resource "cloudflare_web3_hostname" "%[1]s" { + zone_id = "%[2]s" + name = "%[1]s.%[3]s" + target = "ethereum" + description = "test" +} +`, name, zoneID, domain) +} + +func buildWeb3HostnameConfigIPFS(name, zoneID, domain string) string { + return fmt.Sprintf(` +resource "cloudflare_web3_hostname" "%[1]s" { + zone_id = "%[2]s" + name = "%[1]s.%[3]s" + target = "ipfs" + description = "test" + dnslink = "/ipns/onboarding.ipfs.cloudflare.com" +} +`, name, zoneID, domain) +} + +func TestAccCloudflareWeb3HostnameEthereum(t *testing.T) { + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_web3_hostname.%s", rnd) + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + domain := os.Getenv("CLOUDFLARE_DOMAIN") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccessAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: buildWeb3HostnameConfigEthereum(rnd, zoneID, domain), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "zone_id", zoneID), + resource.TestCheckResourceAttr(name, "name", rnd+"."+domain), + resource.TestCheckResourceAttr(name, "target", "ethereum"), + resource.TestCheckResourceAttr(name, "description", "test"), + ), + }, + }, + }) +} + +func TestAccCloudflareWeb3Hostname(t *testing.T) { + rnd := generateRandomResourceName() + name := fmt.Sprintf("cloudflare_web3_hostname.%s", rnd) + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + domain := os.Getenv("CLOUDFLARE_DOMAIN") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccessAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: buildWeb3HostnameConfigIPFS(rnd, zoneID, domain), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "zone_id", zoneID), + resource.TestCheckResourceAttr(name, "name", rnd+"."+domain), + resource.TestCheckResourceAttr(name, "target", "ipfs"), + resource.TestCheckResourceAttr(name, "description", "test"), + resource.TestCheckResourceAttr(name, "dnslink", "/ipns/onboarding.ipfs.cloudflare.com"), + ), + }, + }, + }) +} diff --git a/internal/provider/schema_cloudflare_web3hostname.go b/internal/provider/schema_cloudflare_web3hostname.go new file mode 100644 index 0000000000..cbbf56b12e --- /dev/null +++ b/internal/provider/schema_cloudflare_web3hostname.go @@ -0,0 +1,53 @@ +package provider + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceCloudflareWeb3HostnameSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "zone_id": { + Description: "The zone identifier to target for the resource.", + Type: schema.TypeString, + Required: true, + }, + "name": { + Description: "The hostname that will point to the target gateway via CNAME.", + Type: schema.TypeString, + Required: true, + }, + "target": { + Description: "Target gateway of the hostname.", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"ethereum", "ipfs"}, false), + }, + "description": { + Description: "An optional description of the hostname.", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 500), + }, + "dnslink": { + Description: "DNSLink value used if the target is ipfs.", + Type: schema.TypeString, + Optional: true, + }, + "status": { + Description: "Status of the hostname's activation.", + Type: schema.TypeString, + Computed: true, + }, + "created_on": { + Description: "Creation time.", + Type: schema.TypeString, + Computed: true, + }, + "modified_on": { + Description: "Last modification time.", + Type: schema.TypeString, + Computed: true, + }, + } +}