diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b6fe85a65..9b98881460 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,10 +10,7 @@ on: jobs: lint: - name: lint runs-on: ubuntu-latest - - steps: - uses: actions/checkout@v4 @@ -27,10 +24,9 @@ jobs: - name: Run lints run: ./scripts/lint + test: - name: test runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -43,4 +39,4 @@ jobs: run: ./scripts/bootstrap - name: Run tests - run: ./scripts/test + run: ./scripts/test \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/publish-release.yml similarity index 89% rename from .github/workflows/release.yml rename to .github/workflows/publish-release.yml index 7aa4ac8a08..c4cc0b9f89 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/publish-release.yml @@ -1,4 +1,12 @@ -name: Release +--- +name: Publish Release + +permissions: + contents: write + +concurrency: + group: publish + on: push: tags: @@ -10,8 +18,8 @@ jobs: - name: Cleanup unused directories and tools run: | df -h / - sudo apt-get remove -y '^aspnetcore-.*' '^dotnet-.*' '^llvm-.*' 'php.*' '^mongodb-.*' '^mysql-.*' azure-cli google-chrome-stable firefox powershell mono-devel google-cloud-sdk google-cloud-cli microsoft-edge-stable snapd --fix-missing - sudo apt-get autoremove -y + sudo apt-get remove -y '^aspnetcore-.*' '^dotnet-.*' '^llvm-.*' 'php.*' '^mongodb-.*' '^mysql-.*' azure-cli google-chrome-stable firefox powershell mono-devel google-cloud-sdk google-cloud-cli microsoft-edge-stable snapd --fix-missing + sudo apt-get autoremove -y sudo apt-get clean sudo docker image prune --all --force sudo rm -rf \ @@ -27,7 +35,7 @@ jobs: /usr/local/share/chromium \ /usr/local/share/powershell \ /usr/share/dotnet \ - /usr/share/swift + /usr/share/swift ghcup nuke df -h / - name: Checkout diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000000..38f09200b3 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,22 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'cloudflare/terraform-provider-cloudflare' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./scripts/check-release-environment + env: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 733e50f537..b0b0bbb5f3 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,18 +12,24 @@ builds: ldflags: - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}" goos: + - darwin - freebsd - - windows - linux - - darwin + - windows goarch: - - amd64 - "386" + - amd64 - arm - arm64 ignore: - - goos: darwin - goarch: "386" + - goarch: "386" + goos: darwin + - goarch: arm + goos: windows + - goarch: arm64 + goos: freebsd + - goarch: arm64 + goos: windows binary: "{{ .ProjectName }}_v{{ .Version }}" archives: - formats: [ 'zip' ] diff --git a/.grit/patterns/cloudflare_terraform_v5_attribute_renames_configuration.grit b/.grit/patterns/cloudflare_terraform_v5_attribute_renames_configuration.grit index 8a87957f13..779811fe76 100644 --- a/.grit/patterns/cloudflare_terraform_v5_attribute_renames_configuration.grit +++ b/.grit/patterns/cloudflare_terraform_v5_attribute_renames_configuration.grit @@ -127,6 +127,9 @@ pattern cloudflare_terraform_v5_attribute_renames_configuration() { // cloudflare_tiered_cache `cache_type = $v` as $attribute => `value = $v` where { $attribute <: within `resource "cloudflare_tiered_cache" $_ { $_ }` }, + // cloudflare_dns_record + `hostname = $v` as $hostname => . where { $attribute <: within `resource "cloudflare_dns_record" $_ { $_ }` }, + // cloudflare_web_analytics_site `ruleset_id = $v` as $attribute => `ruleset = { id = $v diff --git a/.grit/patterns/cloudflare_terraform_v5_attribute_renames_state.grit b/.grit/patterns/cloudflare_terraform_v5_attribute_renames_state.grit index dc31c6d67a..f4aa8b96e7 100644 --- a/.grit/patterns/cloudflare_terraform_v5_attribute_renames_state.grit +++ b/.grit/patterns/cloudflare_terraform_v5_attribute_renames_state.grit @@ -224,7 +224,7 @@ pattern cloudflare_terraform_v5_attribute_renames_state() { $instances <: contains `"jump_start": $v` => . } }, - + // cloudflare_record `{ "mode": "managed", "type": "$resource_type", $..., "instances":[$instances] }` where { and { diff --git a/.grit/patterns/cloudflare_terraform_v5_resource_renames_configuration.grit b/.grit/patterns/cloudflare_terraform_v5_resource_renames_configuration.grit index 933f29fca4..cc38989dcd 100644 --- a/.grit/patterns/cloudflare_terraform_v5_resource_renames_configuration.grit +++ b/.grit/patterns/cloudflare_terraform_v5_resource_renames_configuration.grit @@ -27,7 +27,6 @@ pattern cloudflare_terraform_v5_resource_renames_configuration() { `"cloudflare_dlp_custom_profile"` => `"cloudflare_zero_trust_dlp_custom_profile"`, `"cloudflare_dlp_predefined_profile"` => `"cloudflare_zero_trust_dlp_predefined_profile"`, `"cloudflare_dlp_profile"` => `"cloudflare_zero_trust_dlp_profile"`, - `"cloudflare_fallback_domain"` => `"cloudflare_zero_trust_local_domain_fallback"`, `"cloudflare_gateway_app_types"` => `"cloudflare_zero_trust_gateway_app_types"`, `"cloudflare_gre_tunnel"` => `"cloudflare_magic_wan_gre_tunnel"`, `"cloudflare_ipsec_tunnel"` => `"cloudflare_magic_wan_ipsec_tunnel"`, @@ -42,14 +41,13 @@ pattern cloudflare_terraform_v5_resource_renames_configuration() { `"cloudflare_teams_rule"` => `"cloudflare_zero_trust_gateway_policy"`, `"cloudflare_tunnel"` => `"cloudflare_zero_trust_tunnel_cloudflared"`, `"cloudflare_tunnel_config"` => `"cloudflare_zero_trust_tunnel_cloudflared_config"`, - `"cloudflare_tunnel_route"` => `"cloudflare_zero_trust_tunnel_route"`, - `"cloudflare_tunnel_virtual_network"` => `"cloudflare_zero_trust_tunnel_virtual_network"`, + `"cloudflare_tunnel_route"` => `"cloudflare_zero_trust_tunnel_cloudflared_route"`, + `"cloudflare_tunnel_virtual_network"` => `"cloudflare_zero_trust_tunnel_cloudflared_virtual_network"`, `"cloudflare_worker_cron_trigger"` => `"cloudflare_workers_cron_trigger"`, `"cloudflare_worker_domain"` => `"cloudflare_workers_custom_domain"`, `"cloudflare_worker_script"` => `"cloudflare_workers_script"`, `"cloudflare_worker_secret"` => `"cloudflare_workers_secret"`, `"cloudflare_workers_for_platforms_namespace"` => `"cloudflare_workers_for_platforms_dispatch_namespace"`, - `"cloudflare_zone_dnssec"` => `"cloudflare_dns_zone_dnssec"`, `"cloudflare_managed_headers"` => `"cloudflare_managed_transforms"`, } as $old_name where { $old_name <: within `resource $_ { $_ }` diff --git a/.grit/patterns/cloudflare_terraform_v5_resource_renames_state.grit b/.grit/patterns/cloudflare_terraform_v5_resource_renames_state.grit index 127f568ad5..98efa70578 100644 --- a/.grit/patterns/cloudflare_terraform_v5_resource_renames_state.grit +++ b/.grit/patterns/cloudflare_terraform_v5_resource_renames_state.grit @@ -29,7 +29,6 @@ pattern cloudflare_terraform_v5_resource_renames_state() { `"cloudflare_dlp_profile"` => `"cloudflare_zero_trust_dlp_profile"`, `"cloudflare_dlp_custom_profile"` => `"cloudflare_zero_trust_dlp_custom_profile"`, `"cloudflare_dlp_predefined_profile"` => `"cloudflare_zero_trust_dlp_predefined_profile"`, - `"cloudflare_fallback_domain"` => `"cloudflare_zero_trust_local_domain_fallback"`, `"cloudflare_risk_behavior"` => `"cloudflare_zero_trust_risk_behavior"`, `"cloudflare_split_tunnel"` => `"cloudflare_zero_trust_split_tunnels"`, `"cloudflare_teams_account"` => `"cloudflare_zero_trust_gateway_settings"`, @@ -39,8 +38,8 @@ pattern cloudflare_terraform_v5_resource_renames_state() { `"cloudflare_teams_rule"` => `"cloudflare_zero_trust_gateway_policy"`, `"cloudflare_tunnel"` => `"cloudflare_zero_trust_tunnel_cloudflared"`, `"cloudflare_tunnel_config"` => `"cloudflare_zero_trust_tunnel_cloudflared_config"`, - `"cloudflare_tunnel_route"` => `"cloudflare_zero_trust_tunnel_route"`, - `"cloudflare_tunnel_virtual_network"` => `"cloudflare_zero_trust_tunnel_virtual_network"`, + `"cloudflare_tunnel_route"` => `"cloudflare_zero_trust_tunnel_cloudflared_route"`, + `"cloudflare_tunnel_virtual_network"` => `"cloudflare_zero_trust_tunnel_cloudflared_virtual_network"`, // handle dependencies `"cloudflare_access_application.$dep"` => `"cloudflare_zero_trust_access_application.$dep"`, @@ -60,17 +59,14 @@ pattern cloudflare_terraform_v5_resource_renames_state() { `"cloudflare_device_policy_certificates.$dep"` => `"cloudflare_zero_trust_device_certificates.$dep"`, `"cloudflare_device_posture_integration.$dep"` => `"cloudflare_zero_trust_device_posture_integration.$dep"`, `"cloudflare_device_posture_rule.$dep"` => `"cloudflare_zero_trust_device_posture_rule.$dep"`, - `"cloudflare_device_settings_policy.$dep"` => `"cloudflare_zero_trust_device_profiles.$dep"`, `"cloudflare_dlp_custom_profile.$dep"` => `"cloudflare_zero_trust_dlp_custom_profile.$dep"`, `"cloudflare_dlp_predefined_profile.$dep"` => `"cloudflare_zero_trust_dlp_predefined_profile.$dep"`, `"cloudflare_dlp_profile.$dep"` => `"cloudflare_zero_trust_dlp_profile.$dep"`, - `"cloudflare_fallback_domain.$dep"` => `"cloudflare_zero_trust_local_domain_fallback.$dep"`, `"cloudflare_gateway_app_types.$dep"` => `"cloudflare_zero_trust_gateway_app_types.$dep"`, `"cloudflare_gre_tunnel.$dep"` => `"cloudflare_magic_wan_gre_tunnel.$dep"`, `"cloudflare_ipsec_tunnel.$dep"` => `"cloudflare_magic_wan_ipsec_tunnel.$dep"`, `"cloudflare_record.$dep"` => `"cloudflare_dns_record.$dep"`, `"cloudflare_risk_behavior.$dep"` => `"cloudflare_zero_trust_risk_behavior.$dep"`, - `"cloudflare_split_tunnel.$dep"` => `"cloudflare_zero_trust_split_tunnels.$dep"`, `"cloudflare_static_route.$dep"` => `"cloudflare_magic_wan_static_route.$dep"`, `"cloudflare_teams_account.$dep"` => `"cloudflare_zero_trust_gateway_settings.$dep"`, `"cloudflare_teams_list.$dep"` => `"cloudflare_zero_trust_list.$dep"`, @@ -79,14 +75,13 @@ pattern cloudflare_terraform_v5_resource_renames_state() { `"cloudflare_teams_rule.$dep"` => `"cloudflare_zero_trust_gateway_policy.$dep"`, `"cloudflare_tunnel.$dep"` => `"cloudflare_zero_trust_tunnel_cloudflared.$dep"`, `"cloudflare_tunnel_config.$dep"` => `"cloudflare_zero_trust_tunnel_cloudflared_config.$dep"`, - `"cloudflare_tunnel_route.$dep"` => `"cloudflare_zero_trust_tunnel_route.$dep"`, - `"cloudflare_tunnel_virtual_network.$dep"` => `"cloudflare_zero_trust_tunnel_virtual_network.$dep"`, + `"cloudflare_tunnel_route.$dep"` => `"cloudflare_zero_trust_tunnel_cloudflared_route.$dep"`, + `"cloudflare_tunnel_virtual_network.$dep"` => `"cloudflare_zero_trust_tunnel_cloudflared_virtual_network.$dep"`, `"cloudflare_worker_cron_trigger.$dep"` => `"cloudflare_workers_cron_trigger.$dep"`, `"cloudflare_worker_domain.$dep"` => `"cloudflare_workers_custom_domain.$dep"`, `"cloudflare_worker_script.$dep"` => `"cloudflare_workers_script.$dep"`, `"cloudflare_worker_secret.$dep"` => `"cloudflare_workers_secret.$dep"`, `"cloudflare_workers_for_platforms_namespace.$dep"` => `"cloudflare_workers_for_platforms_dispatch_namespace.$dep"`, - `"cloudflare_zone_dnssec.$dep"` => `"cloudflare_dns_zone_dnssec.$dep"`, `"cloudflare_managed_headers.$dep"` => `"cloudflare_managed_transforms.$dep"`, } } diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000000..affd1ab3d1 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "5.1.0" +} diff --git a/.stats.yml b/.stats.yml index 7a6046dba3..c45e5590c6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 1508 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-bc8740036f5c85815dd08ce4d1787a79b09e8133dc24fcdf8c594aad2c5cc69d.yml +configured_endpoints: 1525 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cloudflare%2Fcloudflare-fc562128cab85cd116a8c4e1fe17a0f09a5019da2d1bbe162c476aa999932c4e.yml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..eaaf581a75 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +## 5.1.0 (2025-02-13) + +Full Changelog: [v5.0.0...v5.1.0](https://github.com/cloudflare/terraform-provider-cloudflare/compare/v5.0.0...v5.1.0) + +### Features + +* **api:** disable zero_trust_tunnel_cloudflared_token ([#5128](https://github.com/cloudflare/terraform-provider-cloudflare/issues/5128)) ([df2c3bc](https://github.com/cloudflare/terraform-provider-cloudflare/commit/df2c3bc059f35eddb7b91fef866df7c32165cf05)) +* **api:** enable zero_trust_tunnel_cloudflared_token ([#5127](https://github.com/cloudflare/terraform-provider-cloudflare/issues/5127)) ([1bd200e](https://github.com/cloudflare/terraform-provider-cloudflare/commit/1bd200e88c78565c0ed879e64f8d91473f30e365)) +* **grit:** add more support for dns_record attributes ([3dbe899](https://github.com/cloudflare/terraform-provider-cloudflare/commit/3dbe899a8084a14bb586da181318abe17c7f04ef)) +* various codegen changes ([d91aee1](https://github.com/cloudflare/terraform-provider-cloudflare/commit/d91aee1ef6b403177eb2bdfb5c73a8a3d36b79c3)) + + +### Bug Fixes + +* **grit:** handle inner objects within the object for records ([e7b7bb1](https://github.com/cloudflare/terraform-provider-cloudflare/commit/e7b7bb1e4d4868b2c94304f9a14069eb5e2822b0)) +* **grit:** handle inner objects within the object for records ([c9a5257](https://github.com/cloudflare/terraform-provider-cloudflare/commit/c9a5257d4abbf7f0920415b3ad087789dbfd61ab)) +* **grit:** handle inner objects within the object for records ([ae22af5](https://github.com/cloudflare/terraform-provider-cloudflare/commit/ae22af5228a5b73e3193862c0eccc1325df94d79)) +* **grit:** make pattern names consistent ([0b2ba12](https://github.com/cloudflare/terraform-provider-cloudflare/commit/0b2ba12bb261244c6e9bd24e4b6fa783f26bc0e7)) +* update migration guide to use source, not stdlib ([9d208d6](https://github.com/cloudflare/terraform-provider-cloudflare/commit/9d208d6577f60940ec2bc1d6dcb181fcefbfdfac)) +* use correct name for Grit patterns ([2f8d522](https://github.com/cloudflare/terraform-provider-cloudflare/commit/2f8d5220bc1c76003035c5af885883367bf06867)) + + +### Documentation + +* clean out previously set schema_versions ([fba939d](https://github.com/cloudflare/terraform-provider-cloudflare/commit/fba939df831ff60e451c2f50310eb626687bcdb8)) +* handle cloudflare_record data migration ([9eb450b](https://github.com/cloudflare/terraform-provider-cloudflare/commit/9eb450bb6f146f49a3f6c9a8c73369d747e164f3)) +* regenerate ([bbf53bf](https://github.com/cloudflare/terraform-provider-cloudflare/commit/bbf53bf80a550844e27097487bcc262fbd4d6516)) +* update deprecation dates ([7a8b7d2](https://github.com/cloudflare/terraform-provider-cloudflare/commit/7a8b7d2424fe20a0c83e7a76b069d9b7c042f751)) +* update page_rules migration guidance ([45e30b1](https://github.com/cloudflare/terraform-provider-cloudflare/commit/45e30b1ed3de447d54223d5479ca52fd8609db42)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..1f981a66a1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,62 @@ +## Setting up the environment + +To set up the repository, run: + +```sh +$ ./scripts/bootstrap +$ ./scripts/build +``` + +This will install all the required dependencies and build the Provider binary into the root directory. + +You can also [install go 1.22+ manually](https://go.dev/doc/install). + +## Running the Provider locally + +You can build the provider locally and have your `.tf` files refer to the local build instead of the one in the Hashicorp registry. + +First, build the provider binary: + +```sh +$ ./scripts/build +``` + +Then edit (or create) your `~/.terraformrc` to look something like this: + +```hcl + provider_installation { + dev_overrides { + "cloudflare/cloudflare" = "/local/path/to/this/repo" + } + direct {} + } +``` + +## Running tests + +To execute the schema and unit tests, run: + +```sh +$ ./scripts/test +``` + +Note that this does not run [acceptance tests](https://developer.hashicorp.com/terraform/plugin/framework/acctests) by default, because +those tests interact with real resources in the cloud and could incur fees. + +To enable the running of acceptance tests, use the `TF_ACC` environment variable: + +```sh +$ TF_ACC=1 ./scripts/test +``` + +## Formatting + +This library uses the standard gofmt code formatter: + +```sh +$ ./scripts/format +``` + +## Running Tests + +To run schema tests, diff --git a/README.md b/README.md index 18e2415570..4b9681eecf 100644 --- a/README.md +++ b/README.md @@ -13,20 +13,35 @@ for non-Terraform or service specific information. -``` +```hcl +# Declare the provider and version terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" - version = "~> 5" + version = "~> 5.0.0" } } } + +# Initialize the provider +provider "cloudflare" { + api_token = "Sn3lZJTBX6kkg7OdcBUAxOO963GEIyGQqnFTOFYY" # or set CLOUDFLARE_API_TOKEN env variable +} + +# Configure a resource +resource "cloudflare_zone" "example_zone" { + account = { + id = "023e105f4ecef8ad9ca31a8372d0c353" + } + name = "example.com" + type = "full" +} ``` -And initialize your project by running `terraform init`. +Initialize your project by running `terraform init` in the directory. ## Migrating to Terraform from using the Dashboard diff --git a/docs/data-sources/account_subscription.md b/docs/data-sources/account_subscription.md index e3a1ef64d8..42faa8f0e9 100644 --- a/docs/data-sources/account_subscription.md +++ b/docs/data-sources/account_subscription.md @@ -24,4 +24,28 @@ data "cloudflare_account_subscription" "example_account_subscription" { - `account_id` (String) Identifier +### Read-Only + +- `currency` (String) The monetary unit in which pricing information is displayed. +- `current_period_end` (String) The end of the current period and also when the next billing is due. +- `current_period_start` (String) When the current billing period started. May match initial_period_start if this is the first period. +- `frequency` (String) How often the subscription is renewed automatically. +- `id` (String) Subscription identifier tag. +- `price` (Number) The price of the subscription that will be billed, in US dollars. +- `rate_plan` (Attributes) The rate plan applied to the subscription. (see [below for nested schema](#nestedatt--rate_plan)) +- `state` (String) The state that the subscription is in. + + +### Nested Schema for `rate_plan` + +Read-Only: + +- `currency` (String) The currency applied to the rate plan subscription. +- `externally_managed` (Boolean) Whether this rate plan is managed externally from Cloudflare. +- `id` (String) The ID of the rate plan. +- `is_contract` (Boolean) Whether a rate plan is enterprise-based (or newly adopted term contract). +- `public_name` (String) The full name of the rate plan. +- `scope` (String) The scope that this rate plan applies to. +- `sets` (List of String) The list of sets this rate plan applies to. + diff --git a/docs/data-sources/api_token_permissions_groups.md b/docs/data-sources/api_token_permissions_groups.md new file mode 100644 index 0000000000..9c9352f8f1 --- /dev/null +++ b/docs/data-sources/api_token_permissions_groups.md @@ -0,0 +1,33 @@ +--- +page_title: "cloudflare_api_token_permissions_groups Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_api_token_permissions_groups (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_api_token_permissions_groups" "example_api_token_permissions_groups" { + account_id = "eb78d65290b24279ba6f44721b3ea3c4" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account identifier tag. + +### Read-Only + +- `id` (String) Public ID. +- `name` (String) Permission Group Name +- `scopes` (List of String) Resources to which the Permission Group is scoped + + diff --git a/docs/data-sources/api_token_permissions_groups_list.md b/docs/data-sources/api_token_permissions_groups_list.md index 1885d74858..ce5c40113c 100644 --- a/docs/data-sources/api_token_permissions_groups_list.md +++ b/docs/data-sources/api_token_permissions_groups_list.md @@ -35,4 +35,10 @@ data "cloudflare_api_token_permissions_groups_list" "example_api_token_permissio ### Nested Schema for `result` +Read-Only: + +- `id` (String) Public ID. +- `name` (String) Permission Group Name +- `scopes` (List of String) Resources to which the Permission Group is scoped + diff --git a/docs/data-sources/botnet_feed_config_asn.md b/docs/data-sources/botnet_feed_config_asn.md new file mode 100644 index 0000000000..8ffa986f74 --- /dev/null +++ b/docs/data-sources/botnet_feed_config_asn.md @@ -0,0 +1,31 @@ +--- +page_title: "cloudflare_botnet_feed_config_asn Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_botnet_feed_config_asn (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_botnet_feed_config_asn" "example_botnet_feed_config_asn" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Identifier + +### Read-Only + +- `asn` (Number) + + diff --git a/docs/data-sources/cloudforce_one_request_asset.md b/docs/data-sources/cloudforce_one_request_asset.md index 407f6c6112..70c20c5439 100644 --- a/docs/data-sources/cloudforce_one_request_asset.md +++ b/docs/data-sources/cloudforce_one_request_asset.md @@ -28,4 +28,12 @@ data "cloudflare_cloudforce_one_request_asset" "example_cloudforce_one_request_a - `asset_identifer` (String) UUID - `request_identifier` (String) UUID +### Read-Only + +- `created` (String) Asset creation time +- `description` (String) Asset description +- `file_type` (String) Asset file type +- `id` (Number) Asset ID +- `name` (String) Asset name + diff --git a/docs/data-sources/cloudforce_one_request_message.md b/docs/data-sources/cloudforce_one_request_message.md index 20f840aa74..249587eace 100644 --- a/docs/data-sources/cloudforce_one_request_message.md +++ b/docs/data-sources/cloudforce_one_request_message.md @@ -26,4 +26,13 @@ data "cloudflare_cloudforce_one_request_message" "example_cloudforce_one_request - `account_identifier` (String) Identifier - `request_identifier` (String) UUID +### Read-Only + +- `author` (String) Author of message +- `content` (String) Content of message +- `created` (String) Message creation time +- `id` (Number) Message ID +- `is_follow_on_request` (Boolean) Whether the message is a follow-on request +- `updated` (String) Message last updated time + diff --git a/docs/data-sources/d1_database.md b/docs/data-sources/d1_database.md index 9356ebfd37..05df1b8b87 100644 --- a/docs/data-sources/d1_database.md +++ b/docs/data-sources/d1_database.md @@ -27,17 +27,17 @@ data "cloudflare_d1_database" "example_d1_database" { ### Optional -- `database_id` (String) +- `database_id` (String) D1 database identifier (UUID). - `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) ### Read-Only - `created_at` (String) Specifies the timestamp the resource was created as an ISO8601 string. - `file_size` (Number) The D1 database's size, in bytes. -- `id` (String) The ID of this resource. -- `name` (String) +- `id` (String) D1 database identifier (UUID). +- `name` (String) D1 database name. - `num_tables` (Number) -- `uuid` (String) +- `uuid` (String) D1 database identifier (UUID). - `version` (String) diff --git a/docs/data-sources/d1_databases.md b/docs/data-sources/d1_databases.md index cfca2379f8..408b2ae858 100644 --- a/docs/data-sources/d1_databases.md +++ b/docs/data-sources/d1_databases.md @@ -40,8 +40,8 @@ data "cloudflare_d1_databases" "example_d1_databases" { Read-Only: - `created_at` (String) Specifies the timestamp the resource was created as an ISO8601 string. -- `name` (String) -- `uuid` (String) +- `name` (String) D1 database name. +- `uuid` (String) D1 database identifier (UUID). - `version` (String) diff --git a/docs/data-sources/dns_settings.md b/docs/data-sources/dns_settings.md new file mode 100644 index 0000000000..a52285075f --- /dev/null +++ b/docs/data-sources/dns_settings.md @@ -0,0 +1,77 @@ +--- +page_title: "cloudflare_dns_settings Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_dns_settings (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_dns_settings" "example_dns_settings" { + account_id = "account_id" + zone_id = "zone_id" +} +``` + + +## Schema + +### Optional + +- `account_id` (String) The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. +- `zone_id` (String) The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + +### Read-Only + +- `zone_defaults` (Attributes) (see [below for nested schema](#nestedatt--zone_defaults)) + + +### Nested Schema for `zone_defaults` + +Read-Only: + +- `flatten_all_cnames` (Boolean) Whether to flatten all CNAME records in the zone. Note that, due to DNS limitations, a CNAME record at the zone apex will always be flattened. +- `foundation_dns` (Boolean) Whether to enable Foundation DNS Advanced Nameservers on the zone. +- `internal_dns` (Attributes) Settings for this internal zone. (see [below for nested schema](#nestedatt--zone_defaults--internal_dns)) +- `multi_provider` (Boolean) Whether to enable multi-provider DNS, which causes Cloudflare to activate the zone even when non-Cloudflare NS records exist, and to respect NS records at the zone apex during outbound zone transfers. +- `nameservers` (Attributes) Settings determining the nameservers through which the zone should be available. (see [below for nested schema](#nestedatt--zone_defaults--nameservers)) +- `ns_ttl` (Number) The time to live (TTL) of the zone's nameserver (NS) records. +- `secondary_overrides` (Boolean) Allows a Secondary DNS zone to use (proxied) override records and CNAME flattening at the zone apex. +- `soa` (Attributes) Components of the zone's SOA record. (see [below for nested schema](#nestedatt--zone_defaults--soa)) +- `zone_mode` (String) Whether the zone mode is a regular or CDN/DNS only zone. + + +### Nested Schema for `zone_defaults.internal_dns` + +Read-Only: + +- `reference_zone_id` (String) The ID of the zone to fallback to. + + + +### Nested Schema for `zone_defaults.nameservers` + +Read-Only: + +- `type` (String) Nameserver type + + + +### Nested Schema for `zone_defaults.soa` + +Read-Only: + +- `expire` (Number) Time in seconds of being unable to query the primary server after which secondary servers should stop serving the zone. +- `min_ttl` (Number) The time to live (TTL) for negative caching of records within the zone. +- `mname` (String) The primary nameserver, which may be used for outbound zone transfers. +- `refresh` (Number) Time in seconds after which secondary servers should re-check the SOA record to see if the zone has been updated. +- `retry` (Number) Time in seconds after which secondary servers should retry queries after the primary server was unresponsive. +- `rname` (String) The email address of the zone administrator, with the first label representing the local part of the email address. +- `ttl` (Number) The time to live (TTL) of the SOA record itself. + + diff --git a/docs/data-sources/dns_settings_internal_view.md b/docs/data-sources/dns_settings_internal_view.md new file mode 100644 index 0000000000..08ff45c83a --- /dev/null +++ b/docs/data-sources/dns_settings_internal_view.md @@ -0,0 +1,63 @@ +--- +page_title: "cloudflare_dns_settings_internal_view Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_dns_settings_internal_view (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_dns_settings_internal_view" "example_dns_settings_internal_view" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + view_id = "023e105f4ecef8ad9ca31a8372d0c353" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Identifier + +### Optional + +- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) +- `view_id` (String) Identifier + +### Read-Only + +- `created_time` (String) When the view was created. +- `id` (String) Identifier +- `modified_time` (String) When the view was last modified. +- `name` (String) The name of the view. +- `zones` (List of String) The list of zones linked to this view. + + +### Nested Schema for `filter` + +Optional: + +- `direction` (String) Direction to order DNS views in. +- `match` (String) Whether to match all search requirements or at least one (any). If set to `all`, acts like a logical AND between filters. If set to `any`, acts like a logical OR instead. +- `name` (Attributes) (see [below for nested schema](#nestedatt--filter--name)) +- `order` (String) Field to order DNS views by. +- `zone_id` (String) A zone ID that exists in the zones list for the view. +- `zone_name` (String) A zone name that exists in the zones list for the view. + + +### Nested Schema for `filter.name` + +Optional: + +- `contains` (String) Substring of the DNS view name. +- `endswith` (String) Suffix of the DNS view name. +- `exact` (String) Exact value of the DNS view name. +- `startswith` (String) Prefix of the DNS view name. + + diff --git a/docs/data-sources/dns_settings_internal_views.md b/docs/data-sources/dns_settings_internal_views.md new file mode 100644 index 0000000000..74bddad7ed --- /dev/null +++ b/docs/data-sources/dns_settings_internal_views.md @@ -0,0 +1,72 @@ +--- +page_title: "cloudflare_dns_settings_internal_views Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_dns_settings_internal_views (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_dns_settings_internal_views" "example_dns_settings_internal_views" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + name = { + contains = "view" + endswith = "ew" + exact = "my view" + startswith = "my" + } + order = "name" + zone_id = "ae29bea30e2e427ba9cd8d78b628177b" + zone_name = "www.example.com" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Identifier + +### Optional + +- `direction` (String) Direction to order DNS views in. +- `match` (String) Whether to match all search requirements or at least one (any). If set to `all`, acts like a logical AND between filters. If set to `any`, acts like a logical OR instead. +- `max_items` (Number) Max items to fetch, default: 1000 +- `name` (Attributes) (see [below for nested schema](#nestedatt--name)) +- `order` (String) Field to order DNS views by. +- `zone_id` (String) A zone ID that exists in the zones list for the view. +- `zone_name` (String) A zone name that exists in the zones list for the view. + +### Read-Only + +- `result` (Attributes List) The items returned by the data source (see [below for nested schema](#nestedatt--result)) + + +### Nested Schema for `name` + +Optional: + +- `contains` (String) Substring of the DNS view name. +- `endswith` (String) Suffix of the DNS view name. +- `exact` (String) Exact value of the DNS view name. +- `startswith` (String) Prefix of the DNS view name. + + + +### Nested Schema for `result` + +Read-Only: + +- `created_time` (String) When the view was created. +- `id` (String) Identifier +- `modified_time` (String) When the view was last modified. +- `name` (String) The name of the view. +- `zones` (List of String) The list of zones linked to this view. + + diff --git a/docs/data-sources/filter.md b/docs/data-sources/filter.md index b76ad2d1c4..ae25018303 100644 --- a/docs/data-sources/filter.md +++ b/docs/data-sources/filter.md @@ -23,9 +23,13 @@ data "cloudflare_filter" "example_filter" { ### Required -- `filter_id` (String) The unique identifier of the filter. - `zone_id` (String) Identifier +### Optional + +- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) +- `filter_id` (String) The unique identifier of the filter. + ### Read-Only - `description` (String) An informative summary of the filter. @@ -34,4 +38,15 @@ data "cloudflare_filter" "example_filter" { - `paused` (Boolean) When true, indicates that the filter is currently paused. - `ref` (String) A short reference tag. Allows you to select related filters. + +### Nested Schema for `filter` + +Optional: + +- `description` (String) A case-insensitive string to find in the description. +- `expression` (String) A case-insensitive string to find in the expression. +- `id` (String) The unique identifier of the filter. +- `paused` (Boolean) When true, indicates that the filter is currently paused. +- `ref` (String) The filter ref (a short reference tag) to search for. Must be an exact match. + diff --git a/docs/data-sources/firewall_rule.md b/docs/data-sources/firewall_rule.md index c887a94fde..d5ff7d2d3f 100644 --- a/docs/data-sources/firewall_rule.md +++ b/docs/data-sources/firewall_rule.md @@ -24,33 +24,20 @@ data "cloudflare_firewall_rule" "example_firewall_rule" { ### Required -- `rule_id` (String) The unique identifier of the firewall rule. - `zone_id` (String) Identifier ### Optional -- `id` (String) The unique identifier of the firewall rule. +- `rule_id` (String) The unique identifier of the firewall rule. ### Read-Only - `action` (String) The action to apply to a matched request. The `log` action is only available on an Enterprise plan. - `description` (String) An informative summary of the firewall rule. -- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) +- `id` (String) The unique identifier of the firewall rule. - `paused` (Boolean) When true, indicates that the firewall rule is currently paused. - `priority` (Number) The priority of the rule. Optional value used to define the processing order. A lower number indicates a higher priority. If not provided, rules with a defined priority will be processed before rules without a priority. - `products` (List of String) - `ref` (String) A short reference tag. Allows you to select related firewall rules. - -### Nested Schema for `filter` - -Read-Only: - -- `deleted` (Boolean) When true, indicates that the firewall rule was deleted. -- `description` (String) An informative summary of the filter. -- `expression` (String) The filter expression. For more information, refer to [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). -- `id` (String) The unique identifier of the filter. -- `paused` (Boolean) When true, indicates that the filter is currently paused. -- `ref` (String) A short reference tag. Allows you to select related filters. - diff --git a/docs/data-sources/hostname_tls_setting.md b/docs/data-sources/hostname_tls_setting.md index 3ca9b286f4..94405049b0 100644 --- a/docs/data-sources/hostname_tls_setting.md +++ b/docs/data-sources/hostname_tls_setting.md @@ -26,4 +26,12 @@ data "cloudflare_hostname_tls_setting" "example_hostname_tls_setting" { - `setting_id` (String) The TLS Setting name. - `zone_id` (String) Identifier +### Read-Only + +- `created_at` (String) This is the time the tls setting was originally created for this hostname. +- `hostname` (String) The hostname for which the tls settings are set. +- `status` (String) Deployment status for the given tls setting. +- `updated_at` (String) This is the time the tls setting was updated. +- `value` (Number) The tls setting value. + diff --git a/docs/data-sources/ip_ranges.md b/docs/data-sources/ip_ranges.md new file mode 100644 index 0000000000..0f93520d92 --- /dev/null +++ b/docs/data-sources/ip_ranges.md @@ -0,0 +1,34 @@ +--- +page_title: "cloudflare_ip_ranges Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_ip_ranges (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_ip_ranges" "example_ip_ranges" { + networks = "networks" +} +``` + + +## Schema + +### Optional + +- `networks` (String) Specified as `jdcloud` to list IPs used by JD Cloud data centers. + +### Read-Only + +- `etag` (String) A digest of the IP data. Useful for determining if the data has changed. +- `ipv4_cidrs` (List of String) List of Cloudflare IPv4 CIDR addresses. +- `ipv6_cidrs` (List of String) List of Cloudflare IPv6 CIDR addresses. +- `jdcloud_cidrs` (List of String) List IPv4 and IPv6 CIDRs, only populated if `?networks=jdcloud` is used. + + diff --git a/docs/data-sources/logpush_dataset_job.md b/docs/data-sources/logpush_dataset_job.md index 74cb55d76a..9279e47b3a 100644 --- a/docs/data-sources/logpush_dataset_job.md +++ b/docs/data-sources/logpush_dataset_job.md @@ -31,4 +31,40 @@ data "cloudflare_logpush_dataset_job" "example_logpush_dataset_job" { - `account_id` (String) The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. - `zone_id` (String) The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. +### Read-Only + +- `dataset` (String) Name of the dataset. A list of supported datasets can be found on the [Developer Docs](https://developers.cloudflare.com/logs/reference/log-fields/). +- `destination_conf` (String) Uniquely identifies a resource (such as an s3 bucket) where data will be pushed. Additional configuration parameters supported by the destination may be included. +- `enabled` (Boolean) Flag that indicates if the job is enabled. +- `error_message` (String) If not null, the job is currently failing. Failures are usually repetitive (example: no permissions to write to destination bucket). Only the last failure is recorded. On successful execution of a job the error_message and last_error are set to null. +- `frequency` (String) This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files. +- `id` (Number) Unique id of the job. +- `kind` (String) The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset. +- `last_complete` (String) Records the last time for which logs have been successfully pushed. If the last successful push was for logs range 2018-07-23T10:00:00Z to 2018-07-23T10:01:00Z then the value of this field will be 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and hasn't run yet then the field will be empty. +- `last_error` (String) Records the last time the job failed. If not null, the job is currently failing. If null, the job has either never failed or has run successfully at least once since last failure. See also the error_message field. +- `logpull_options` (String) This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately. +- `max_upload_bytes` (Number) The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind. +- `max_upload_interval_seconds` (Number) The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind. +- `max_upload_records` (Number) The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind. +- `name` (String) Optional human readable job name. Not unique. Cloudflare suggests that you set this to a meaningful string, like the domain name, to make it easier to identify your job. +- `output_options` (Attributes) The structured replacement for `logpull_options`. When including this field, the `logpull_option` field will be ignored. (see [below for nested schema](#nestedatt--output_options)) + + +### Nested Schema for `output_options` + +Read-Only: + +- `batch_prefix` (String) String to be prepended before each batch. +- `batch_suffix` (String) String to be appended after each batch. +- `cve_2021_4428` (Boolean) If set to true, will cause all occurrences of `${` in the generated files to be replaced with `x{`. +- `field_delimiter` (String) String to join fields. This field be ignored when `record_template` is set. +- `field_names` (List of String) List of field names to be included in the Logpush output. For the moment, there is no option to add all fields at once, so you must specify all the fields names you are interested in. +- `output_type` (String) Specifies the output type, such as `ndjson` or `csv`. This sets default values for the rest of the settings, depending on the chosen output type. Some formatting rules, like string quoting, are different between output types. +- `record_delimiter` (String) String to be inserted in-between the records as separator. +- `record_prefix` (String) String to be prepended before each record. +- `record_suffix` (String) String to be appended after each record. +- `record_template` (String) String to use as template for each record instead of the default comma-separated list. All fields used in the template must be present in `field_names` as well, otherwise they will end up as null. Format as a Go `text/template` without any standard functions, like conditionals, loops, sub-templates, etc. +- `sample_rate` (Number) Floating number to specify sampling rate. Sampling is applied on top of filtering, and regardless of the current `sample_interval` of the data. +- `timestamp_format` (String) String to specify the format for timestamps, such as `unixnano`, `unix`, or `rfc3339`. + diff --git a/docs/data-sources/magic_transit_site.md b/docs/data-sources/magic_transit_site.md index 87ff077198..0a0c0d29e7 100644 --- a/docs/data-sources/magic_transit_site.md +++ b/docs/data-sources/magic_transit_site.md @@ -45,7 +45,7 @@ data "cloudflare_magic_transit_site" "example_magic_transit_site" { Optional: -- `connector_identifier` (String) Identifier +- `connectorid` (String) Identifier diff --git a/docs/data-sources/magic_transit_site_lan.md b/docs/data-sources/magic_transit_site_lan.md index 2931ddf8b3..5ddc23205e 100644 --- a/docs/data-sources/magic_transit_site_lan.md +++ b/docs/data-sources/magic_transit_site_lan.md @@ -25,6 +25,9 @@ data "cloudflare_magic_transit_site_lan" "example_magic_transit_site_lan" { ### Required - `account_id` (String) Identifier + +### Optional + - `lan_id` (String) Identifier ### Read-Only @@ -92,6 +95,7 @@ Read-Only: - `dhcp_pool_end` (String) A valid IPv4 address. - `dhcp_pool_start` (String) A valid IPv4 address. - `dns_server` (String) A valid IPv4 address. +- `dns_servers` (List of String) - `reservations` (Map of String) Mapping of MAC addresses to IP addresses diff --git a/docs/data-sources/magic_transit_site_lans.md b/docs/data-sources/magic_transit_site_lans.md index a3f0f055b9..e24e020995 100644 --- a/docs/data-sources/magic_transit_site_lans.md +++ b/docs/data-sources/magic_transit_site_lans.md @@ -102,6 +102,7 @@ Read-Only: - `dhcp_pool_end` (String) A valid IPv4 address. - `dhcp_pool_start` (String) A valid IPv4 address. - `dns_server` (String) A valid IPv4 address. +- `dns_servers` (List of String) - `reservations` (Map of String) Mapping of MAC addresses to IP addresses diff --git a/docs/data-sources/magic_transit_site_wan.md b/docs/data-sources/magic_transit_site_wan.md index 7ac04d53c8..7775a971b5 100644 --- a/docs/data-sources/magic_transit_site_wan.md +++ b/docs/data-sources/magic_transit_site_wan.md @@ -25,6 +25,9 @@ data "cloudflare_magic_transit_site_wan" "example_magic_transit_site_wan" { ### Required - `account_id` (String) Identifier + +### Optional + - `wan_id` (String) Identifier ### Read-Only diff --git a/docs/data-sources/magic_transit_sites.md b/docs/data-sources/magic_transit_sites.md index 6e8854a3df..3843b5ab7d 100644 --- a/docs/data-sources/magic_transit_sites.md +++ b/docs/data-sources/magic_transit_sites.md @@ -14,7 +14,7 @@ description: |- ```terraform data "cloudflare_magic_transit_sites" "example_magic_transit_sites" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" - connector_identifier = "023e105f4ecef8ad9ca31a8372d0c353" + connectorid = "023e105f4ecef8ad9ca31a8372d0c353" } ``` @@ -27,7 +27,7 @@ data "cloudflare_magic_transit_sites" "example_magic_transit_sites" { ### Optional -- `connector_identifier` (String) Identifier +- `connectorid` (String) Identifier - `max_items` (Number) Max items to fetch, default: 1000 ### Read-Only diff --git a/docs/data-sources/permission_group.md b/docs/data-sources/permission_group.md index 339bf6cc59..6180922beb 100644 --- a/docs/data-sources/permission_group.md +++ b/docs/data-sources/permission_group.md @@ -21,9 +21,10 @@ data "cloudflare_permission_group" "example_permission_group" { ## Schema -### Required +### Optional - `account_id` (String) Account identifier tag. +- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) - `permission_group_id` (String) Permission Group identifier tag. ### Read-Only @@ -32,6 +33,20 @@ data "cloudflare_permission_group" "example_permission_group" { - `meta` (Attributes) Attributes associated to the permission group. (see [below for nested schema](#nestedatt--meta)) - `name` (String) Name of the group. + +### Nested Schema for `filter` + +Required: + +- `account_id` (String) Account identifier tag. + +Optional: + +- `id` (String) ID of the permission group to be fetched. +- `label` (String) Label of the permission group to be fetched. +- `name` (String) Name of the permission group to be fetched. + + ### Nested Schema for `meta` diff --git a/docs/data-sources/permission_groups.md b/docs/data-sources/permission_groups.md index 37ac14861a..dc487b5e3d 100644 --- a/docs/data-sources/permission_groups.md +++ b/docs/data-sources/permission_groups.md @@ -41,4 +41,18 @@ data "cloudflare_permission_groups" "example_permission_groups" { ### Nested Schema for `result` +Read-Only: + +- `id` (String) Identifier of the group. +- `meta` (Attributes) Attributes associated to the permission group. (see [below for nested schema](#nestedatt--result--meta)) +- `name` (String) Name of the group. + + +### Nested Schema for `result.meta` + +Read-Only: + +- `key` (String) +- `value` (String) + diff --git a/docs/data-sources/queue_consumer.md b/docs/data-sources/queue_consumer.md index 2e9272f4f5..2ffe9c6ebe 100644 --- a/docs/data-sources/queue_consumer.md +++ b/docs/data-sources/queue_consumer.md @@ -24,6 +24,27 @@ data "cloudflare_queue_consumer" "example_queue_consumer" { ### Required - `account_id` (String) A Resource identifier. + +### Read-Only + +- `consumer_id` (String) A Resource identifier. +- `created_on` (String) - `queue_id` (String) A Resource identifier. +- `script` (String) Name of a Worker +- `script_name` (String) Name of a Worker +- `settings` (Attributes) (see [below for nested schema](#nestedatt--settings)) +- `type` (String) + + +### Nested Schema for `settings` + +Read-Only: + +- `batch_size` (Number) The maximum number of messages to include in a batch. +- `max_concurrency` (Number) Maximum number of concurrent consumers that may consume from this Queue. Set to `null` to automatically opt in to the platform's maximum (recommended). +- `max_retries` (Number) The maximum number of retries +- `max_wait_time_ms` (Number) The number of milliseconds to wait for a batch to fill up before attempting to deliver it +- `retry_delay` (Number) The number of seconds to delay before making the message available for another attempt. +- `visibility_timeout_ms` (Number) The number of milliseconds that a message is exclusively leased. After the timeout, the message becomes available for another attempt. diff --git a/docs/data-sources/r2_bucket_cors.md b/docs/data-sources/r2_bucket_cors.md new file mode 100644 index 0000000000..1a8b939301 --- /dev/null +++ b/docs/data-sources/r2_bucket_cors.md @@ -0,0 +1,52 @@ +--- +page_title: "cloudflare_r2_bucket_cors Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_cors (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_bucket_cors" "example_r2_bucket_cors" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Read-Only + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Read-Only: + +- `allowed` (Attributes) Object specifying allowed origins, methods and headers for this CORS rule. (see [below for nested schema](#nestedatt--rules--allowed)) +- `expose_headers` (List of String) Specifies the headers that can be exposed back, and accessed by, the JavaScript making the cross-origin request. If you need to access headers beyond the safelisted response headers, such as Content-Encoding or cf-cache-status, you must specify it here. +- `id` (String) Identifier for this rule +- `max_age_seconds` (Number) Specifies the amount of time (in seconds) browsers are allowed to cache CORS preflight responses. Browsers may limit this to 2 hours or less, even if the maximum value (86400) is specified. + + +### Nested Schema for `rules.allowed` + +Read-Only: + +- `headers` (List of String) Specifies the value for the Access-Control-Allow-Headers header R2 sets when requesting objects in this bucket from a browser. Cross-origin requests that include custom headers (e.g. x-user-id) should specify these headers as AllowedHeaders. +- `methods` (List of String) Specifies the value for the Access-Control-Allow-Methods header R2 sets when requesting objects in a bucket from a browser. +- `origins` (List of String) Specifies the value for the Access-Control-Allow-Origin header R2 sets when requesting objects in a bucket from a browser. + + diff --git a/docs/data-sources/r2_bucket_event_notification.md b/docs/data-sources/r2_bucket_event_notification.md new file mode 100644 index 0000000000..c6909b2b41 --- /dev/null +++ b/docs/data-sources/r2_bucket_event_notification.md @@ -0,0 +1,54 @@ +--- +page_title: "cloudflare_r2_bucket_event_notification Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_event_notification (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_bucket_event_notification" "example_r2_bucket_event_notification" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Read-Only + +- `queues` (Attributes List) List of queues associated with the bucket. (see [below for nested schema](#nestedatt--queues)) + + +### Nested Schema for `queues` + +Read-Only: + +- `queue_id` (String) Queue ID +- `queue_name` (String) Name of the queue +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--queues--rules)) + + +### Nested Schema for `queues.rules` + +Read-Only: + +- `actions` (List of String) Array of R2 object actions that will trigger notifications +- `created_at` (String) Timestamp when the rule was created +- `description` (String) A description that can be used to identify the event notification rule after creation +- `prefix` (String) Notifications will be sent only for objects with this prefix +- `rule_id` (String) Rule ID +- `suffix` (String) Notifications will be sent only for objects with this suffix + + diff --git a/docs/data-sources/r2_bucket_lifecycle.md b/docs/data-sources/r2_bucket_lifecycle.md new file mode 100644 index 0000000000..35b94fb167 --- /dev/null +++ b/docs/data-sources/r2_bucket_lifecycle.md @@ -0,0 +1,105 @@ +--- +page_title: "cloudflare_r2_bucket_lifecycle Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_lifecycle (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_bucket_lifecycle" "example_r2_bucket_lifecycle" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Read-Only + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Read-Only: + +- `abort_multipart_uploads_transition` (Attributes) Transition to abort ongoing multipart uploads (see [below for nested schema](#nestedatt--rules--abort_multipart_uploads_transition)) +- `conditions` (Attributes) Conditions that apply to all transitions of this rule (see [below for nested schema](#nestedatt--rules--conditions)) +- `delete_objects_transition` (Attributes) Transition to delete objects (see [below for nested schema](#nestedatt--rules--delete_objects_transition)) +- `enabled` (Boolean) Whether or not this rule is in effect +- `id` (String) Unique identifier for this rule +- `storage_class_transitions` (Attributes List) Transitions to change the storage class of objects (see [below for nested schema](#nestedatt--rules--storage_class_transitions)) + + +### Nested Schema for `rules.abort_multipart_uploads_transition` + +Read-Only: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--abort_multipart_uploads_transition--condition)) + + +### Nested Schema for `rules.abort_multipart_uploads_transition.condition` + +Read-Only: + +- `max_age` (Number) +- `type` (String) + + + + +### Nested Schema for `rules.conditions` + +Read-Only: + +- `prefix` (String) Transitions will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads + + + +### Nested Schema for `rules.delete_objects_transition` + +Read-Only: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--delete_objects_transition--condition)) + + +### Nested Schema for `rules.delete_objects_transition.condition` + +Read-Only: + +- `date` (String) +- `max_age` (Number) +- `type` (String) + + + + +### Nested Schema for `rules.storage_class_transitions` + +Read-Only: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--storage_class_transitions--condition)) +- `storage_class` (String) + + +### Nested Schema for `rules.storage_class_transitions.condition` + +Read-Only: + +- `date` (String) +- `max_age` (Number) +- `type` (String) + + diff --git a/docs/data-sources/r2_bucket_lock.md b/docs/data-sources/r2_bucket_lock.md new file mode 100644 index 0000000000..9f44962221 --- /dev/null +++ b/docs/data-sources/r2_bucket_lock.md @@ -0,0 +1,52 @@ +--- +page_title: "cloudflare_r2_bucket_lock Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_lock (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_bucket_lock" "example_r2_bucket_lock" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Read-Only + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Read-Only: + +- `condition` (Attributes) Condition to apply a lock rule to an object for how long in seconds (see [below for nested schema](#nestedatt--rules--condition)) +- `enabled` (Boolean) Whether or not this rule is in effect +- `id` (String) Unique identifier for this rule +- `prefix` (String) Rule will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads + + +### Nested Schema for `rules.condition` + +Read-Only: + +- `date` (String) +- `max_age_seconds` (Number) +- `type` (String) + + diff --git a/docs/data-sources/r2_bucket_sippy.md b/docs/data-sources/r2_bucket_sippy.md new file mode 100644 index 0000000000..6c8341a53b --- /dev/null +++ b/docs/data-sources/r2_bucket_sippy.md @@ -0,0 +1,56 @@ +--- +page_title: "cloudflare_r2_bucket_sippy Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_sippy (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_bucket_sippy" "example_r2_bucket_sippy" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Read-Only + +- `destination` (Attributes) Details about the configured destination bucket (see [below for nested schema](#nestedatt--destination)) +- `enabled` (Boolean) State of Sippy for this bucket +- `source` (Attributes) Details about the configured source bucket (see [below for nested schema](#nestedatt--source)) + + +### Nested Schema for `destination` + +Read-Only: + +- `access_key_id` (String) ID of the Cloudflare API token used when writing objects to this +bucket +- `account` (String) +- `bucket` (String) Name of the bucket on the provider +- `provider` (String) + + + +### Nested Schema for `source` + +Read-Only: + +- `bucket` (String) Name of the bucket on the provider +- `provider` (String) +- `region` (String) Region where the bucket resides (AWS only) + + diff --git a/docs/data-sources/r2_custom_domain.md b/docs/data-sources/r2_custom_domain.md new file mode 100644 index 0000000000..52a6bf4c46 --- /dev/null +++ b/docs/data-sources/r2_custom_domain.md @@ -0,0 +1,48 @@ +--- +page_title: "cloudflare_r2_custom_domain Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_custom_domain (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_r2_custom_domain" "example_r2_custom_domain" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + domain_name = "example-domain/custom-domain.com" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket +- `domain_name` (String) Name of the custom domain + +### Read-Only + +- `domain` (String) Domain name of the custom domain to be added +- `enabled` (Boolean) Whether this bucket is publicly accessible at the specified custom domain +- `min_tls` (String) Minimum TLS Version the custom domain will accept for incoming connections. If not set, defaults to 1.0. +- `status` (Attributes) (see [below for nested schema](#nestedatt--status)) +- `zone_id` (String) Zone ID of the custom domain resides in +- `zone_name` (String) Zone that the custom domain resides in + + +### Nested Schema for `status` + +Read-Only: + +- `ownership` (String) Ownership status of the domain +- `ssl` (String) SSL certificate status + + diff --git a/docs/data-sources/resource_groups.md b/docs/data-sources/resource_groups.md index 1e58b8ed45..ff218b048f 100644 --- a/docs/data-sources/resource_groups.md +++ b/docs/data-sources/resource_groups.md @@ -39,4 +39,35 @@ data "cloudflare_resource_groups" "example_resource_groups" { ### Nested Schema for `result` +Read-Only: + +- `id` (String) Identifier of the group. +- `meta` (Attributes) Attributes associated to the resource group. (see [below for nested schema](#nestedatt--result--meta)) +- `name` (String) Name of the resource group. +- `scope` (Attributes List) The scope associated to the resource group (see [below for nested schema](#nestedatt--result--scope)) + + +### Nested Schema for `result.meta` + +Read-Only: + +- `key` (String) +- `value` (String) + + + +### Nested Schema for `result.scope` + +Read-Only: + +- `key` (String) This is a combination of pre-defined resource name and identifier (like Account ID etc.) +- `objects` (Attributes List) A list of scope objects for additional context. (see [below for nested schema](#nestedatt--result--scope--objects)) + + +### Nested Schema for `result.scope.objects` + +Read-Only: + +- `key` (String) This is a combination of pre-defined resource name and identifier (like Zone ID etc.) + diff --git a/docs/data-sources/spectrum_application.md b/docs/data-sources/spectrum_application.md index af04bca1d1..76d15b91ab 100644 --- a/docs/data-sources/spectrum_application.md +++ b/docs/data-sources/spectrum_application.md @@ -23,8 +23,8 @@ data "cloudflare_spectrum_application" "example_spectrum_application" { ### Required -- `app_id` (String) Identifier -- `zone_id` (String) Identifier +- `app_id` (String) App identifier. +- `zone_id` (String) Zone identifier. ### Read-Only diff --git a/docs/data-sources/spectrum_applications.md b/docs/data-sources/spectrum_applications.md index 6bda6f3630..9174284f9b 100644 --- a/docs/data-sources/spectrum_applications.md +++ b/docs/data-sources/spectrum_applications.md @@ -22,7 +22,7 @@ data "cloudflare_spectrum_applications" "example_spectrum_applications" { ### Required -- `zone_id` (String) Identifier +- `zone_id` (String) Zone identifier. ### Optional diff --git a/docs/data-sources/stream_audio_track.md b/docs/data-sources/stream_audio_track.md index 5019b3cc00..b60b79721d 100644 --- a/docs/data-sources/stream_audio_track.md +++ b/docs/data-sources/stream_audio_track.md @@ -26,4 +26,11 @@ data "cloudflare_stream_audio_track" "example_stream_audio_track" { - `account_id` (String) The account identifier tag. - `identifier` (String) A Cloudflare-generated unique identifier for a media item. +### Read-Only + +- `default` (Boolean) Denotes whether the audio track will be played by default in a player. +- `label` (String) A string to uniquely identify the track amongst other audio track labels for the specified video. +- `status` (String) Specifies the processing status of the video. +- `uid` (String) A Cloudflare-generated unique identifier for a media item. + diff --git a/docs/data-sources/stream_key.md b/docs/data-sources/stream_key.md index a727d2bd1d..a4a15f1ef9 100644 --- a/docs/data-sources/stream_key.md +++ b/docs/data-sources/stream_key.md @@ -24,4 +24,9 @@ data "cloudflare_stream_key" "example_stream_key" { - `account_id` (String) Identifier +### Read-Only + +- `created` (String) The date and time a signing key was created. +- `id` (String) Identifier + diff --git a/docs/data-sources/waiting_room_rules.md b/docs/data-sources/waiting_room_rules.md index 295e3ec996..bbc6658b75 100644 --- a/docs/data-sources/waiting_room_rules.md +++ b/docs/data-sources/waiting_room_rules.md @@ -26,4 +26,14 @@ data "cloudflare_waiting_room_rules" "example_waiting_room_rules" { - `waiting_room_id` (String) - `zone_id` (String) Identifier +### Read-Only + +- `action` (String) The action to take when the expression matches. +- `description` (String) The description of the rule. +- `enabled` (Boolean) When set to true, the rule is enabled. +- `expression` (String) Criteria defining when there is a match for the current rule. +- `id` (String) The ID of the rule. +- `last_updated` (String) +- `version` (String) The version of the rule. + diff --git a/docs/data-sources/workers_route.md b/docs/data-sources/workers_route.md new file mode 100644 index 0000000000..79ba0d56f7 --- /dev/null +++ b/docs/data-sources/workers_route.md @@ -0,0 +1,35 @@ +--- +page_title: "cloudflare_workers_route Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_workers_route (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_workers_route" "example_workers_route" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" + route_id = "023e105f4ecef8ad9ca31a8372d0c353" +} +``` + + +## Schema + +### Required + +- `route_id` (String) Identifier +- `zone_id` (String) Identifier + +### Read-Only + +- `id` (String) Identifier +- `pattern` (String) +- `script` (String) Name of the script, used in URLs and route configuration. + + diff --git a/docs/data-sources/workers_routes.md b/docs/data-sources/workers_routes.md new file mode 100644 index 0000000000..d3c8ad450f --- /dev/null +++ b/docs/data-sources/workers_routes.md @@ -0,0 +1,44 @@ +--- +page_title: "cloudflare_workers_routes Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_workers_routes (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_workers_routes" "example_workers_routes" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" +} +``` + + +## Schema + +### Required + +- `zone_id` (String) Identifier + +### Optional + +- `max_items` (Number) Max items to fetch, default: 1000 + +### Read-Only + +- `result` (Attributes List) The items returned by the data source (see [below for nested schema](#nestedatt--result)) + + +### Nested Schema for `result` + +Read-Only: + +- `id` (String) Identifier +- `pattern` (String) +- `script` (String) Name of the script, used in URLs and route configuration. + + diff --git a/docs/data-sources/zero_trust_access_application.md b/docs/data-sources/zero_trust_access_application.md index f081ae5007..b474fb1749 100644 --- a/docs/data-sources/zero_trust_access_application.md +++ b/docs/data-sources/zero_trust_access_application.md @@ -203,6 +203,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--service_token)) @@ -346,6 +347,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.exclude.okta` @@ -397,6 +406,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--include--service_token)) @@ -540,6 +550,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.include.okta` @@ -591,6 +609,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--require--service_token)) @@ -734,6 +753,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.require.okta` @@ -811,7 +838,16 @@ Read-Only: Read-Only: - `name` (String) The name of the IdP attribute. -- `name_by_idp` (Map of String) A mapping from IdP ID to attribute name. +- `name_by_idp` (Attributes List) A mapping from IdP ID to attribute name. (see [below for nested schema](#nestedatt--saas_app--custom_attributes--source--name_by_idp)) + + +### Nested Schema for `saas_app.custom_attributes.source.name_by_idp` + +Read-Only: + +- `idp_id` (String) The UID of the IdP. +- `source_name` (String) The name of the IdP provided attribute. + diff --git a/docs/data-sources/zero_trust_access_applications.md b/docs/data-sources/zero_trust_access_applications.md index 59f8e97ee1..47b0909809 100644 --- a/docs/data-sources/zero_trust_access_applications.md +++ b/docs/data-sources/zero_trust_access_applications.md @@ -205,6 +205,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--policies--exclude--service_token)) @@ -348,6 +349,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.policies.exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.policies.exclude.okta` @@ -399,6 +408,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--policies--include--service_token)) @@ -542,6 +552,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.policies.include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.policies.include.okta` @@ -593,6 +611,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--policies--require--service_token)) @@ -736,6 +755,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.policies.require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.policies.require.okta` @@ -813,7 +840,16 @@ Read-Only: Read-Only: - `name` (String) The name of the IdP attribute. -- `name_by_idp` (Map of String) A mapping from IdP ID to attribute name. +- `name_by_idp` (Attributes List) A mapping from IdP ID to attribute name. (see [below for nested schema](#nestedatt--result--saas_app--custom_attributes--source--name_by_idp)) + + +### Nested Schema for `result.saas_app.custom_attributes.source.name_by_idp` + +Read-Only: + +- `idp_id` (String) The UID of the IdP. +- `source_name` (String) The name of the IdP provided attribute. + diff --git a/docs/data-sources/zero_trust_access_group.md b/docs/data-sources/zero_trust_access_group.md index 0357ac34cb..93f592b5ae 100644 --- a/docs/data-sources/zero_trust_access_group.md +++ b/docs/data-sources/zero_trust_access_group.md @@ -72,6 +72,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--exclude--service_token)) @@ -215,6 +216,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `exclude.okta` @@ -266,6 +275,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--include--service_token)) @@ -409,6 +419,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `include.okta` @@ -460,6 +478,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--is_default--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--is_default--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--is_default--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--is_default--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--is_default--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--is_default--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--is_default--service_token)) @@ -603,6 +622,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `is_default.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `is_default.okta` @@ -654,6 +681,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--require--service_token)) @@ -797,6 +825,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `require.okta` diff --git a/docs/data-sources/zero_trust_access_groups.md b/docs/data-sources/zero_trust_access_groups.md index 8430524cd7..f5dec3e08f 100644 --- a/docs/data-sources/zero_trust_access_groups.md +++ b/docs/data-sources/zero_trust_access_groups.md @@ -72,6 +72,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--service_token)) @@ -215,6 +216,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.exclude.okta` @@ -266,6 +275,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--include--service_token)) @@ -409,6 +419,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.include.okta` @@ -460,6 +478,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--is_default--service_token)) @@ -603,6 +622,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.is_default.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.is_default.okta` @@ -654,6 +681,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--require--service_token)) @@ -797,6 +825,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.require.okta` diff --git a/docs/data-sources/zero_trust_access_infrastructure_target.md b/docs/data-sources/zero_trust_access_infrastructure_target.md index 006e0da385..dff8c600f6 100644 --- a/docs/data-sources/zero_trust_access_infrastructure_target.md +++ b/docs/data-sources/zero_trust_access_infrastructure_target.md @@ -48,13 +48,26 @@ Optional: - `direction` (String) The sorting direction. - `hostname` (String) Hostname of a target - `hostname_contains` (String) Partial match to the hostname of a target +- `ip_like` (String) Filters for targets whose IP addresses look like the specified string. +Supports `*` as a wildcard character - `ip_v4` (String) IPv4 address of the target - `ip_v6` (String) IPv6 address of the target - `ips` (List of String) Filters for targets that have any of the following IP addresses. Specify `ips` multiple times in query parameter to build list of candidates. +- `ipv4_end` (String) Defines an IPv4 filter range's ending value (inclusive). Requires +`ipv4_start` to be specified as well. +- `ipv4_start` (String) Defines an IPv4 filter range's starting value (inclusive). Requires +`ipv4_end` to be specified as well. +- `ipv6_end` (String) Defines an IPv6 filter range's ending value (inclusive). Requires +`ipv6_start` to be specified as well. +- `ipv6_start` (String) Defines an IPv6 filter range's starting value (inclusive). Requires +`ipv6_end` to be specified as well. - `modified_after` (String) Date and time at which the target was modified after (inclusive) - `modified_before` (String) Date and time at which the target was modified before (inclusive) - `order` (String) The field to sort by. +- `target_ids` (List of String) Filters for targets that have any of the following UUIDs. Specify +`target_ids` multiple times in query parameter to build list of +candidates. - `virtual_network_id` (String) Private virtual network identifier of the target diff --git a/docs/data-sources/zero_trust_access_infrastructure_targets.md b/docs/data-sources/zero_trust_access_infrastructure_targets.md index b1fca8c87f..b7e3a6aa56 100644 --- a/docs/data-sources/zero_trust_access_infrastructure_targets.md +++ b/docs/data-sources/zero_trust_access_infrastructure_targets.md @@ -19,12 +19,18 @@ data "cloudflare_zero_trust_access_infrastructure_targets" "example_zero_trust_a direction = "asc" hostname = "hostname" hostname_contains = "hostname_contains" + ip_like = "ip_like" ip_v4 = "ip_v4" ip_v6 = "ip_v6" ips = ["string"] + ipv4_end = "ipv4_end" + ipv4_start = "ipv4_start" + ipv6_end = "ipv6_end" + ipv6_start = "ipv6_start" modified_after = "2019-12-27T18:11:19.117Z" modified_before = "2019-12-27T18:11:19.117Z" order = "hostname" + target_ids = ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"] virtual_network_id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e" } ``` @@ -43,14 +49,27 @@ data "cloudflare_zero_trust_access_infrastructure_targets" "example_zero_trust_a - `direction` (String) The sorting direction. - `hostname` (String) Hostname of a target - `hostname_contains` (String) Partial match to the hostname of a target +- `ip_like` (String) Filters for targets whose IP addresses look like the specified string. +Supports `*` as a wildcard character - `ip_v4` (String) IPv4 address of the target - `ip_v6` (String) IPv6 address of the target - `ips` (List of String) Filters for targets that have any of the following IP addresses. Specify `ips` multiple times in query parameter to build list of candidates. +- `ipv4_end` (String) Defines an IPv4 filter range's ending value (inclusive). Requires +`ipv4_start` to be specified as well. +- `ipv4_start` (String) Defines an IPv4 filter range's starting value (inclusive). Requires +`ipv4_end` to be specified as well. +- `ipv6_end` (String) Defines an IPv6 filter range's ending value (inclusive). Requires +`ipv6_start` to be specified as well. +- `ipv6_start` (String) Defines an IPv6 filter range's starting value (inclusive). Requires +`ipv6_end` to be specified as well. - `max_items` (Number) Max items to fetch, default: 1000 - `modified_after` (String) Date and time at which the target was modified after (inclusive) - `modified_before` (String) Date and time at which the target was modified before (inclusive) - `order` (String) The field to sort by. +- `target_ids` (List of String) Filters for targets that have any of the following UUIDs. Specify +`target_ids` multiple times in query parameter to build list of +candidates. - `virtual_network_id` (String) Private virtual network identifier of the target ### Read-Only diff --git a/docs/data-sources/zero_trust_access_mtls_hostname_settings.md b/docs/data-sources/zero_trust_access_mtls_hostname_settings.md index 5c6ddc7491..0a52ddc8dc 100644 --- a/docs/data-sources/zero_trust_access_mtls_hostname_settings.md +++ b/docs/data-sources/zero_trust_access_mtls_hostname_settings.md @@ -26,4 +26,10 @@ data "cloudflare_zero_trust_access_mtls_hostname_settings" "example_zero_trust_a - `account_id` (String) The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. - `zone_id` (String) The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. +### Read-Only + +- `china_network` (Boolean) Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled. +- `client_certificate_forwarding` (Boolean) Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin. +- `hostname` (String) The hostname that these settings apply to. + diff --git a/docs/data-sources/zero_trust_access_policies.md b/docs/data-sources/zero_trust_access_policies.md index 45dd4dbd49..b9c99dfcbf 100644 --- a/docs/data-sources/zero_trust_access_policies.md +++ b/docs/data-sources/zero_trust_access_policies.md @@ -87,6 +87,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--exclude--service_token)) @@ -230,6 +231,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.exclude.okta` @@ -281,6 +290,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--include--service_token)) @@ -424,6 +434,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.include.okta` @@ -475,6 +493,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--result--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--result--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--result--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--result--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--result--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--result--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--result--require--service_token)) @@ -618,6 +637,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `result.require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `result.require.okta` diff --git a/docs/data-sources/zero_trust_access_policy.md b/docs/data-sources/zero_trust_access_policy.md index 80cc968cd8..f7e7b1c7b3 100644 --- a/docs/data-sources/zero_trust_access_policy.md +++ b/docs/data-sources/zero_trust_access_policy.md @@ -81,6 +81,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--exclude--service_token)) @@ -224,6 +225,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `exclude.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `exclude.okta` @@ -275,6 +284,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--include--service_token)) @@ -418,6 +428,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `include.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `include.okta` @@ -469,6 +487,7 @@ Read-Only: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--require--service_token)) @@ -612,6 +631,14 @@ Read-Only: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `require.login_method` + +Read-Only: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `require.okta` diff --git a/docs/data-sources/zero_trust_device_custom_profile_local_domain_fallback.md b/docs/data-sources/zero_trust_device_custom_profile_local_domain_fallback.md index 71ddf357a8..4552896e80 100644 --- a/docs/data-sources/zero_trust_device_custom_profile_local_domain_fallback.md +++ b/docs/data-sources/zero_trust_device_custom_profile_local_domain_fallback.md @@ -26,4 +26,10 @@ data "cloudflare_zero_trust_device_custom_profile_local_domain_fallback" "exampl - `account_id` (String) - `policy_id` (String) Device ID. +### Read-Only + +- `description` (String) A description of the fallback domain, displayed in the client UI. +- `dns_server` (List of String) A list of IP addresses to handle domain resolution. +- `suffix` (String) The domain suffix to match when resolving locally. + diff --git a/docs/data-sources/zero_trust_device_default_profile_local_domain_fallback.md b/docs/data-sources/zero_trust_device_default_profile_local_domain_fallback.md index 2164ef4775..2275f6d3bf 100644 --- a/docs/data-sources/zero_trust_device_default_profile_local_domain_fallback.md +++ b/docs/data-sources/zero_trust_device_default_profile_local_domain_fallback.md @@ -24,4 +24,10 @@ data "cloudflare_zero_trust_device_default_profile_local_domain_fallback" "examp - `account_id` (String) +### Read-Only + +- `description` (String) A description of the fallback domain, displayed in the client UI. +- `dns_server` (List of String) A list of IP addresses to handle domain resolution. +- `suffix` (String) The domain suffix to match when resolving locally. + diff --git a/docs/data-sources/zero_trust_device_posture_integration.md b/docs/data-sources/zero_trust_device_posture_integration.md index 737dd8d785..8aa0f956f3 100644 --- a/docs/data-sources/zero_trust_device_posture_integration.md +++ b/docs/data-sources/zero_trust_device_posture_integration.md @@ -31,7 +31,7 @@ data "cloudflare_zero_trust_device_posture_integration" "example_zero_trust_devi ### Read-Only -- `config` (Attributes) The Workspace One Config Response. (see [below for nested schema](#nestedatt--config)) +- `config` (Attributes) The configuration object containing third-party integration information. (see [below for nested schema](#nestedatt--config)) - `id` (String) API UUID. - `interval` (String) The interval between each posture check with the third-party API. Use `m` for minutes (e.g. `5m`) and `h` for hours (e.g. `12h`). - `name` (String) The name of the device posture integration. diff --git a/docs/data-sources/zero_trust_device_posture_integrations.md b/docs/data-sources/zero_trust_device_posture_integrations.md index 5cde842b4e..60a42f08fe 100644 --- a/docs/data-sources/zero_trust_device_posture_integrations.md +++ b/docs/data-sources/zero_trust_device_posture_integrations.md @@ -37,7 +37,7 @@ data "cloudflare_zero_trust_device_posture_integrations" "example_zero_trust_dev Read-Only: -- `config` (Attributes) The Workspace One Config Response. (see [below for nested schema](#nestedatt--result--config)) +- `config` (Attributes) The configuration object containing third-party integration information. (see [below for nested schema](#nestedatt--result--config)) - `id` (String) API UUID. - `interval` (String) The interval between each posture check with the third-party API. Use `m` for minutes (e.g. `5m`) and `h` for hours (e.g. `12h`). - `name` (String) The name of the device posture integration. diff --git a/docs/data-sources/zero_trust_dlp_custom_profile.md b/docs/data-sources/zero_trust_dlp_custom_profile.md index 752e65abcd..b24c6d55f6 100644 --- a/docs/data-sources/zero_trust_dlp_custom_profile.md +++ b/docs/data-sources/zero_trust_dlp_custom_profile.md @@ -28,6 +28,7 @@ data "cloudflare_zero_trust_dlp_custom_profile" "example_zero_trust_dlp_custom_p ### Read-Only +- `ai_context_enabled` (Boolean) - `allowed_match_count` (Number) Related DLP policies will trigger when the match count exceeds the number set. - `confidence_threshold` (String) - `context_awareness` (Attributes) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedatt--context_awareness)) @@ -80,6 +81,7 @@ Read-Only: Read-Only: +- `ai_context_available` (Boolean) - `available` (Boolean) Indicates whether this entry can be made more or less sensitive by setting a confidence threshold. Profiles that use an entry with `available` set to true can use confidence thresholds diff --git a/docs/data-sources/zero_trust_dlp_entries.md b/docs/data-sources/zero_trust_dlp_entries.md index 1d14815c1a..9537767504 100644 --- a/docs/data-sources/zero_trust_dlp_entries.md +++ b/docs/data-sources/zero_trust_dlp_entries.md @@ -54,6 +54,7 @@ Read-Only: Read-Only: +- `ai_context_available` (Boolean) - `available` (Boolean) Indicates whether this entry can be made more or less sensitive by setting a confidence threshold. Profiles that use an entry with `available` set to true can use confidence thresholds diff --git a/docs/data-sources/zero_trust_dlp_entry.md b/docs/data-sources/zero_trust_dlp_entry.md index 7d3486383d..c53bf7d093 100644 --- a/docs/data-sources/zero_trust_dlp_entry.md +++ b/docs/data-sources/zero_trust_dlp_entry.md @@ -48,6 +48,7 @@ data "cloudflare_zero_trust_dlp_entry" "example_zero_trust_dlp_entry" { Read-Only: +- `ai_context_available` (Boolean) - `available` (Boolean) Indicates whether this entry can be made more or less sensitive by setting a confidence threshold. Profiles that use an entry with `available` set to true can use confidence thresholds diff --git a/docs/data-sources/zero_trust_dlp_predefined_profile.md b/docs/data-sources/zero_trust_dlp_predefined_profile.md index fe3b5197d3..7964802a75 100644 --- a/docs/data-sources/zero_trust_dlp_predefined_profile.md +++ b/docs/data-sources/zero_trust_dlp_predefined_profile.md @@ -28,6 +28,7 @@ data "cloudflare_zero_trust_dlp_predefined_profile" "example_zero_trust_dlp_pred ### Read-Only +- `ai_context_enabled` (Boolean) - `allowed_match_count` (Number) Related DLP policies will trigger when the match count exceeds the number set. - `confidence_threshold` (String) - `context_awareness` (Attributes) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedatt--context_awareness)) @@ -80,6 +81,7 @@ Read-Only: Read-Only: +- `ai_context_available` (Boolean) - `available` (Boolean) Indicates whether this entry can be made more or less sensitive by setting a confidence threshold. Profiles that use an entry with `available` set to true can use confidence thresholds diff --git a/docs/data-sources/zero_trust_gateway_logging.md b/docs/data-sources/zero_trust_gateway_logging.md new file mode 100644 index 0000000000..c135d2eedb --- /dev/null +++ b/docs/data-sources/zero_trust_gateway_logging.md @@ -0,0 +1,41 @@ +--- +page_title: "cloudflare_zero_trust_gateway_logging Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_zero_trust_gateway_logging (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_zero_trust_gateway_logging" "example_zero_trust_gateway_logging" { + account_id = "699d98642c564d2e855e9661899b7252" +} +``` + + +## Schema + +### Required + +- `account_id` (String) + +### Read-Only + +- `redact_pii` (Boolean) Redact personally identifiable information from activity logging (PII fields are: source IP, user email, user ID, device ID, URL, referrer, user agent). +- `settings_by_rule_type` (Attributes) Logging settings by rule type. (see [below for nested schema](#nestedatt--settings_by_rule_type)) + + +### Nested Schema for `settings_by_rule_type` + +Read-Only: + +- `dns` (String) Logging settings for DNS firewall. +- `http` (String) Logging settings for HTTP/HTTPS firewall. +- `l4` (String) Logging settings for Network firewall. + + diff --git a/docs/data-sources/zero_trust_gateway_proxy_endpoint.md b/docs/data-sources/zero_trust_gateway_proxy_endpoint.md index 6ae11d0e20..407e2e96e1 100644 --- a/docs/data-sources/zero_trust_gateway_proxy_endpoint.md +++ b/docs/data-sources/zero_trust_gateway_proxy_endpoint.md @@ -26,4 +26,13 @@ data "cloudflare_zero_trust_gateway_proxy_endpoint" "example_zero_trust_gateway_ - `account_id` (String) - `proxy_endpoint_id` (String) +### Read-Only + +- `created_at` (String) +- `id` (String) The ID of this resource. +- `ips` (List of String) A list of CIDRs to restrict ingress connections. +- `name` (String) The name of the proxy endpoint. +- `subdomain` (String) The subdomain to be used as the destination in the proxy client. +- `updated_at` (String) + diff --git a/docs/data-sources/zero_trust_tunnel_cloudflared_token.md b/docs/data-sources/zero_trust_tunnel_cloudflared_token.md new file mode 100644 index 0000000000..608f2755b7 --- /dev/null +++ b/docs/data-sources/zero_trust_tunnel_cloudflared_token.md @@ -0,0 +1,29 @@ +--- +page_title: "cloudflare_zero_trust_tunnel_cloudflared_token Data Source - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_zero_trust_tunnel_cloudflared_token (Data Source) + + + +## Example Usage + +```terraform +data "cloudflare_zero_trust_tunnel_cloudflared_token" "example_zero_trust_tunnel_cloudflared_token" { + account_id = "699d98642c564d2e855e9661899b7252" + tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Cloudflare account ID +- `tunnel_id` (String) UUID of the tunnel. + + diff --git a/docs/data-sources/zone.md b/docs/data-sources/zone.md index 063611bc2b..33df4a0be3 100644 --- a/docs/data-sources/zone.md +++ b/docs/data-sources/zone.md @@ -50,6 +50,7 @@ benefits. - `type` (String) A full zone implies that DNS is hosted with Cloudflare. A partial zone is typically a partner-hosted zone or a CNAME setup. - `vanity_name_servers` (List of String) An array of domains used for custom name servers. This is only available for Business and Enterprise plans. +- `verification_key` (String) Verification key for partial zone setup. ### Nested Schema for `filter` diff --git a/docs/data-sources/zone_cache_reserve.md b/docs/data-sources/zone_cache_reserve.md index c6990f89ab..0e4c2daed2 100644 --- a/docs/data-sources/zone_cache_reserve.md +++ b/docs/data-sources/zone_cache_reserve.md @@ -27,8 +27,8 @@ data "cloudflare_zone_cache_reserve" "example_zone_cache_reserve" { ### Read-Only - `editable` (Boolean) Whether the setting is editable +- `id` (String) ID of the zone setting. - `modified_on` (String) Last time this setting was modified. - `value` (String) The value of the feature -- `zone_setting_id` (String) ID of the zone setting. diff --git a/docs/data-sources/zones.md b/docs/data-sources/zones.md index af56e61e5e..a68cf09692 100644 --- a/docs/data-sources/zones.md +++ b/docs/data-sources/zones.md @@ -94,6 +94,7 @@ benefits. - `type` (String) A full zone implies that DNS is hosted with Cloudflare. A partial zone is typically a partner-hosted zone or a CNAME setup. - `vanity_name_servers` (List of String) An array of domains used for custom name servers. This is only available for Business and Enterprise plans. +- `verification_key` (String) Verification key for partial zone setup. ### Nested Schema for `result.account` diff --git a/docs/guides/migrating-renamed-resources.md b/docs/guides/migrating-renamed-resources.md index 294105d722..5c3a3530d7 100644 --- a/docs/guides/migrating-renamed-resources.md +++ b/docs/guides/migrating-renamed-resources.md @@ -17,7 +17,7 @@ description: Guide for handling renamed resources in the Cloudflare Provider migration. - Make backups of your configuration and state file. -~> It is recommended to do perform testing in a non-production, non-critical +~> It is recommended to perform testing in a non-production, non-critical environment or a small subset resources before performing the changes to all resources. diff --git a/docs/guides/version-5-upgrade.md b/docs/guides/version-5-upgrade.md index 0a60bacb07..47106a90cd 100644 --- a/docs/guides/version-5-upgrade.md +++ b/docs/guides/version-5-upgrade.md @@ -42,40 +42,63 @@ provider "cloudflare" { } ``` -## Resource renames +## Approach -For an in depth guide on how to perform migrations for resources or datasources that -have been renamed, check out [migrating renamed resources]. +At a high level, there are two parts to the migration. The first is the migration of the +configuration (HCL) and the second is the migration of the state. Within each of those +sections, there is the need to migrate attributes and potentially the resource rename. -The pattern files for v5 resource renames are: +### Automatic -- `cloudflare_terraform_v5_resource_renames_configuration` -- `cloudflare_terraform_v5_resource_renames_state` +For assisting with automatic migrations, we have provided [GritQL] patterns. -## Automatic migration - -For assisting with automatic migrations, we have provided a [GritQL] pattern. - -This will allow you to rewrite the parts of your Terraform configuration (not state) -that have changed automatically. Once you [install Grit], you can run the following -command in the directory where your Terraform configuration is located. +This will allow you to rewrite the parts of your Terraform configuration and state +that have changed automatically. Once you [install Grit], you can run the commands +in the directory where your Terraform configuration is located. ~> While all efforts have been made to ease the transition, some of the more complex resources that may contain difficult to reconcile resources have been intentionally skipped for the automatic migration and are only manually documented. If you are using modules or other dynamic features of HCL, the provided codemods may not be -as effective. We recommend reviewing the migration notes below to verify all the +as effective. We recommend reviewing the manual migration notes to verify all the changes. -```bash -$ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5 -``` - We recommend ensuring you are using version control for these changes or make a backup prior to initiating the change to enable reverting if needed. +1. Update the resource attributes in your configuration. _Note: this will not update + your state file. The next step will determine how your state file is updated._ + ```bash + $ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5 + ``` +2. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the attribute changes. If you are choosing to + use the provided GritQL patterns, the pattern name is + `cloudflare_terraform_v5_attribute_renames_state`. Otherwise, you can reimport the + resources without manually managing the state file. +3. Perform the resource renames. _Note: this will not update your state file. + The next step will determine how your state file is updated._ + ```bash + $ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5_resource_renames_configuration + ``` +4. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the resource renames. If you are choosing to + use the provided GritQL patterns, the pattern name is + `cloudflare_terraform_v5_resource_renames_state`. + +### Manual + +1. Update the resource attributes in your configuration using the migration notes. +2. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the attribute changes. +3. Perform the resource renames using the migration notes. +4. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the resource renames. + +## Changelog + ```grit language hcl @@ -152,7 +175,7 @@ cloudflare_terraform_v5() ## cloudflare_device_settings_policy -- Renamed to `cloudflare_zero_trust_device_profiles` +- Renamed to `cloudflare_zero_trust_device_custom_profile` or `cloudflare_zero_trust_device_custom_profile` depending on your intended usage. ## cloudflare_dlp_custom_profile @@ -166,7 +189,7 @@ cloudflare_terraform_v5() - Renamed to `cloudflare_zero_trust_custom_dlp_profile` or `cloudflare_zero_trust_predefined_dlp_profile` depending on which you are targeting. -## cloudflare_fallback_domain +## cloudflare_fallback_domain / cloudflare_zero_trust_local_fallback_domain - Renamed to `cloudflare_zero_trust_device_custom_profile_local_domain_fallback` or `cloudflare_zero_trust_device_default_profile_local_domain_fallback` depending on which you are targeting. @@ -192,7 +215,7 @@ cloudflare_terraform_v5() ## cloudflare_split_tunnel -- Renamed to `cloudflare_zero_trust_split_tunnels` +- Renamed to `cloudflare_zero_trust_device_default_profile` and `cloudflare_zero_trust_device_custom_profile` depending on which you are targeting. ## cloudflare_static_route @@ -228,11 +251,11 @@ cloudflare_terraform_v5() ## cloudflare_tunnel_route -- Renamed to `cloudflare_zero_trust_tunnel_route` +- Renamed to `cloudflare_zero_trust_tunnel_cloudflared_route` ## cloudflare_tunnel_virtual_network -- Renamed to `cloudflare_zero_trust_tunnel_virtual_network` +- Renamed to `cloudflare_zero_trust_tunnel_cloudflared_virtual_network` ## cloudflare_worker_cron_trigger @@ -254,10 +277,6 @@ cloudflare_terraform_v5() - Renamed to `cloudflare_workers_for_platforms_dispatch_namespace` -## cloudflare_zone_dnssec - -- Renamed to `cloudflare_dns_zone_dnssec` - ## cloudflare_managed_headers - Renamed to `cloudflare_managed_transforms` @@ -830,6 +849,10 @@ resource "cloudflare_api_token" "example" { } ``` +## cloudflare_custom_page + +- `cloudflare_custom_page` has been removed. + ## cloudflare_zone_settings_override - `cloudflare_zone_settings_override` has been removed. Use `cloudflare_zone_setting` instead on a per setting basis. @@ -1118,6 +1141,9 @@ resource "cloudflare_api_token" "example" { ## cloudflare_dns_record - `data` is now a single nested attribute (`data = { ... }`) instead of a block (`data { ... }`). +- `data.flag` is now a number (`flag = 0`) instead of a string (`flag = "0"`). +- `hostname` has been removed. Instead, you should use a combination of data source and resource attributes to get the same value. +- `allow_overwrite` has been removed. ## cloudflare_zero_trust_risk_behavior @@ -1138,7 +1164,7 @@ resource "cloudflare_api_token" "example" { - `from_list` is now a list of objects (`from_list = [{ ... }]`) instead of multiple block attribute (`from_list { ... }`). - `from_value` is now a list of objects (`from_value = [{ ... }]`) instead of multiple block attribute (`from_value { ... }`). - `header` is now a list of objects (`header = [{ ... }]`) instead of multiple block attribute (`header { ... }`). -- `headers` is now a list of objects (`headers = [{ ... }]`) instead of multiple block attribute (`headers { ... }`). +- `headers` is now a map of attributes keyed by the name instead of multiple block attribute (`headers { ... }`). - `host` is now a list of objects (`host = [{ ... }]`) instead of multiple block attribute (`host { ... }`). - `logging` is now a single nested attribute (`logging = { ... }`) instead of a block (`logging { ... }`). - `matched_data` is now a list of objects (`matched_data = [{ ... }]`) instead of multiple block attribute (`matched_data { ... }`). @@ -1228,9 +1254,6 @@ resource "cloudflare_api_token" "example" { ## cloudflare_workers_script - `name` is now `script_name`. -- `compatibility_date` is now `metadata.compatibility_date`. -- `compatibility_flags` is now `metadata.compatibility_flags`. -- `tags` is now `metadata.tags`. - `analytics_engine_binding` is now a list of objects (`analytics_engine_binding = [{ ... }]`) instead of multiple block attribute (`analytics_engine_binding { ... }`). - `d1_database_binding` is now a list of objects (`d1_database_binding = [{ ... }]`) instead of multiple block attribute (`d1_database_binding { ... }`). - `kv_namespace_binding` is now a list of objects (`kv_namespace_binding = [{ ... }]`) instead of multiple block attribute (`kv_namespace_binding { ... }`). @@ -1249,6 +1272,7 @@ resource "cloudflare_api_token" "example" { ## cloudflare_page_rule +- `actions`is now a single nested attribute instead of a block. - `ignore = true` is now `exclude = ["*"]` - `ignore = false` is now `include = ["*"]` - `cache_ttl_by_status` is now a map (`cache_ttl_by_status = { ... }`) instead of a list of objects (`cache_ttl_by_status = [{ ... }]`) @@ -1258,16 +1282,14 @@ Before ``` resource "cloudflare_page_rule" "example" { target = "example.com" - actions = [ - { - cache_key_fields = { - query_string = { - ignore = true - ignore = false - } + actions { + cache_key_fields = { + query_string = { + ignore = true + ignore = false } } - ] + } } ``` @@ -1276,16 +1298,14 @@ After ``` resource "cloudflare_page_rule" "example" { target = "example.com" - actions = [ - { - cache_key_fields = { - query_string = { - exclude = ["*"] - include = ["*"] - } + actions = { + cache_key_fields = { + query_string = { + exclude = ["*"] + include = ["*"] } } - ] + } } ``` diff --git a/docs/resources/account_subscription.md b/docs/resources/account_subscription.md index bd3f458266..6bc87b5cd7 100644 --- a/docs/resources/account_subscription.md +++ b/docs/resources/account_subscription.md @@ -40,6 +40,15 @@ resource "cloudflare_account_subscription" "example_account_subscription" { - `rate_plan` (Attributes) The rate plan applied to the subscription. (see [below for nested schema](#nestedatt--rate_plan)) - `subscription_identifier` (String) Subscription identifier tag. +### Read-Only + +- `currency` (String) The monetary unit in which pricing information is displayed. +- `current_period_end` (String) The end of the current period and also when the next billing is due. +- `current_period_start` (String) When the current billing period started. May match initial_period_start if this is the first period. +- `id` (String) Subscription identifier tag. +- `price` (Number) The price of the subscription that will be billed, in US dollars. +- `state` (String) The state that the subscription is in. + ### Nested Schema for `rate_plan` diff --git a/docs/resources/account_token.md b/docs/resources/account_token.md index ecb9429988..66d744dd93 100644 --- a/docs/resources/account_token.md +++ b/docs/resources/account_token.md @@ -18,11 +18,13 @@ resource "cloudflare_account_token" "example_account_token" { policies = [{ effect = "allow" permission_groups = [{ + id = "c8fed203ed3043cba015a93ad1616f1f" meta = { key = "key" value = "value" } }, { + id = "82e64a83756745bbbb1c9c2701bf816b" meta = { key = "key" value = "value" @@ -84,13 +86,16 @@ Read-Only: ### Nested Schema for `policies.permission_groups` +Required: + +- `id` (String) Identifier of the group. + Optional: - `meta` (Attributes) Attributes associated to the permission group. (see [below for nested schema](#nestedatt--policies--permission_groups--meta)) Read-Only: -- `id` (String) Identifier of the group. - `name` (String) Name of the group. diff --git a/docs/resources/api_token.md b/docs/resources/api_token.md index af91a4dcd0..36c57cfe96 100644 --- a/docs/resources/api_token.md +++ b/docs/resources/api_token.md @@ -17,11 +17,13 @@ resource "cloudflare_api_token" "example_api_token" { policies = [{ effect = "allow" permission_groups = [{ + id = "c8fed203ed3043cba015a93ad1616f1f" meta = { key = "key" value = "value" } }, { + id = "82e64a83756745bbbb1c9c2701bf816b" meta = { key = "key" value = "value" diff --git a/docs/resources/authenticated_origin_pulls.md b/docs/resources/authenticated_origin_pulls.md index 5da62994cc..433ed762b0 100644 --- a/docs/resources/authenticated_origin_pulls.md +++ b/docs/resources/authenticated_origin_pulls.md @@ -44,7 +44,9 @@ resource "cloudflare_authenticated_origin_pulls" "example_authenticated_origin_p - `created_at` (String) The time when the certificate was created. - `enabled` (Boolean) Indicates whether hostname-level authenticated origin pulls is enabled. A null value voids the association. - `expires_on` (String) The date when the certificate expires. +- `id` (String) Identifier - `issuer` (String) The certificate authority that issued the certificate. +- `private_key` (String) The hostname certificate's private key. - `serial_number` (String) The serial number on the uploaded certificate. - `signature` (String) The type of hash used for the certificate. - `status` (String) Status of the certificate or the association. diff --git a/docs/resources/cloud_connector_rules.md b/docs/resources/cloud_connector_rules.md index 61358ce055..5a6a23b20d 100644 --- a/docs/resources/cloud_connector_rules.md +++ b/docs/resources/cloud_connector_rules.md @@ -35,6 +35,15 @@ resource "cloudflare_cloud_connector_rules" "example_cloud_connector_rules" { - `rules` (Attributes List) List of Cloud Connector rules (see [below for nested schema](#nestedatt--rules)) - `zone_id` (String) Identifier +### Read-Only + +- `cloud_provider` (String) Cloud Provider type +- `description` (String) +- `enabled` (Boolean) +- `expression` (String) +- `id` (String) The ID of this resource. +- `parameters` (Attributes) Parameters of Cloud Connector Rule (see [below for nested schema](#nestedatt--parameters)) + ### Nested Schema for `rules` @@ -55,3 +64,12 @@ Optional: - `host` (String) Host to perform Cloud Connection to + + +### Nested Schema for `parameters` + +Read-Only: + +- `host` (String) Host to perform Cloud Connection to + + diff --git a/docs/resources/cloudforce_one_request_asset.md b/docs/resources/cloudforce_one_request_asset.md index 6b0133f8a0..95705fc557 100644 --- a/docs/resources/cloudforce_one_request_asset.md +++ b/docs/resources/cloudforce_one_request_asset.md @@ -32,7 +32,6 @@ resource "cloudflare_cloudforce_one_request_asset" "example_cloudforce_one_reque ### Optional -- `asset_identifer` (String) UUID - `source` (String) Asset file to upload ### Read-Only @@ -43,4 +42,10 @@ resource "cloudflare_cloudforce_one_request_asset" "example_cloudforce_one_reque - `id` (Number) Asset ID - `name` (String) Asset name +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_cloudforce_one_request_asset.example '//' +``` diff --git a/docs/resources/content_scanning_expression.md b/docs/resources/content_scanning_expression.md index bc54efcd9f..f580123103 100644 --- a/docs/resources/content_scanning_expression.md +++ b/docs/resources/content_scanning_expression.md @@ -28,9 +28,10 @@ resource "cloudflare_content_scanning_expression" "example_content_scanning_expr - `body` (Attributes List) (see [below for nested schema](#nestedatt--body)) - `zone_id` (String) Identifier -### Optional +### Read-Only -- `expression_id` (String) Identifier +- `id` (String) The unique ID for this custom scan expression +- `payload` (String) Ruleset expression to use in matching content objects ### Nested Schema for `body` diff --git a/docs/resources/custom_hostname.md b/docs/resources/custom_hostname.md index 4de28ff4e1..90d6b60971 100644 --- a/docs/resources/custom_hostname.md +++ b/docs/resources/custom_hostname.md @@ -19,6 +19,20 @@ resource "cloudflare_custom_hostname" "example_custom_hostname" { bundle_method = "ubiquitous" certificate_authority = "digicert" cloudflare_branding = false + custom_cert_bundle = [{ + custom_certificate = < +### Nested Schema for `ssl.custom_cert_bundle` + +Required: + +- `custom_certificate` (String) If a custom uploaded certificate is used. +- `custom_key` (String) The key for a custom uploaded certificate. + + ### Nested Schema for `ssl.settings` diff --git a/docs/resources/d1_database.md b/docs/resources/d1_database.md index a8d826a37f..80b42bb719 100644 --- a/docs/resources/d1_database.md +++ b/docs/resources/d1_database.md @@ -28,7 +28,7 @@ resource "cloudflare_d1_database" "example_d1_database" { ### Required - `account_id` (String) Account identifier tag. -- `name` (String) +- `name` (String) D1 database name. ### Optional @@ -38,9 +38,9 @@ resource "cloudflare_d1_database" "example_d1_database" { - `created_at` (String) Specifies the timestamp the resource was created as an ISO8601 string. - `file_size` (Number) The D1 database's size, in bytes. -- `id` (String) The ID of this resource. +- `id` (String) D1 database identifier (UUID). - `num_tables` (Number) -- `uuid` (String) +- `uuid` (String) D1 database identifier (UUID). - `version` (String) ## Import diff --git a/docs/resources/dns_firewall.md b/docs/resources/dns_firewall.md index be1e8f22af..81e963c86c 100644 --- a/docs/resources/dns_firewall.md +++ b/docs/resources/dns_firewall.md @@ -14,6 +14,8 @@ description: |- ```terraform resource "cloudflare_dns_firewall" "example_dns_firewall" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" + name = "My Awesome DNS Firewall cluster" + upstream_ips = ["192.0.2.1", "198.51.100.1", "2001:DB8:100::CF"] attack_mitigation = { enabled = true only_when_upstream_unhealthy = false @@ -22,11 +24,9 @@ resource "cloudflare_dns_firewall" "example_dns_firewall" { ecs_fallback = false maximum_cache_ttl = 900 minimum_cache_ttl = 60 - name = "My Awesome DNS Firewall cluster" negative_cache_ttl = 900 ratelimit = 600 retries = 2 - upstream_ips = ["192.0.2.1", "198.51.100.1", "string"] } ``` @@ -36,6 +36,8 @@ resource "cloudflare_dns_firewall" "example_dns_firewall" { ### Required - `account_id` (String) Identifier +- `name` (String) DNS Firewall cluster name +- `upstream_ips` (List of String) ### Optional @@ -44,11 +46,9 @@ resource "cloudflare_dns_firewall" "example_dns_firewall" { - `ecs_fallback` (Boolean) Whether to forward client IP (resolver) subnet if no EDNS Client Subnet is sent - `maximum_cache_ttl` (Number) Maximum DNS cache TTL This setting sets an upper bound on DNS TTLs for purposes of caching between DNS Firewall and the upstream servers. Higher TTLs will be decreased to the maximum defined here for caching purposes. - `minimum_cache_ttl` (Number) Minimum DNS cache TTL This setting sets a lower bound on DNS TTLs for purposes of caching between DNS Firewall and the upstream servers. Lower TTLs will be increased to the minimum defined here for caching purposes. -- `name` (String) DNS Firewall cluster name - `negative_cache_ttl` (Number) Negative DNS cache TTL This setting controls how long DNS Firewall should cache negative responses (e.g., NXDOMAIN) from the upstream servers. - `ratelimit` (Number) Ratelimit in queries per second per datacenter (applies to DNS queries sent to the upstream nameservers configured on the cluster) - `retries` (Number) Number of retries for fetching DNS responses from upstream nameservers (not counting the initial attempt) -- `upstream_ips` (List of String) ### Read-Only diff --git a/docs/resources/dns_record.md b/docs/resources/dns_record.md index 63ba4663cc..1bdb9fcbec 100644 --- a/docs/resources/dns_record.md +++ b/docs/resources/dns_record.md @@ -69,7 +69,7 @@ Optional: - `digest` (String) Digest. - `digest_type` (Number) Digest Type. - `fingerprint` (String) fingerprint. -- `flags` (Dynamic) Flags for the CAA record. +- `flags` (Number) Flags for the CAA record. - `key_tag` (Number) Key Tag. - `lat_degrees` (Number) Degrees of latitude. - `lat_direction` (String) Latitude direction. diff --git a/docs/resources/dns_settings.md b/docs/resources/dns_settings.md new file mode 100644 index 0000000000..028b542864 --- /dev/null +++ b/docs/resources/dns_settings.md @@ -0,0 +1,96 @@ +--- +page_title: "cloudflare_dns_settings Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_dns_settings (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_dns_settings" "example_dns_settings" { + zone_id = "zone_id" + zone_defaults = { + flatten_all_cnames = false + foundation_dns = false + internal_dns = { + reference_zone_id = "reference_zone_id" + } + multi_provider = false + nameservers = { + type = "cloudflare.standard" + } + ns_ttl = 86400 + secondary_overrides = false + soa = { + expire = 604800 + min_ttl = 1800 + mname = "kristina.ns.cloudflare.com" + refresh = 10000 + retry = 2400 + rname = "admin.example.com" + ttl = 3600 + } + zone_mode = "standard" + } +} +``` + + +## Schema + +### Optional + +- `account_id` (String) The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. +- `zone_defaults` (Attributes) (see [below for nested schema](#nestedatt--zone_defaults)) +- `zone_id` (String) The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. + + +### Nested Schema for `zone_defaults` + +Optional: + +- `flatten_all_cnames` (Boolean) Whether to flatten all CNAME records in the zone. Note that, due to DNS limitations, a CNAME record at the zone apex will always be flattened. +- `foundation_dns` (Boolean) Whether to enable Foundation DNS Advanced Nameservers on the zone. +- `internal_dns` (Attributes) Settings for this internal zone. (see [below for nested schema](#nestedatt--zone_defaults--internal_dns)) +- `multi_provider` (Boolean) Whether to enable multi-provider DNS, which causes Cloudflare to activate the zone even when non-Cloudflare NS records exist, and to respect NS records at the zone apex during outbound zone transfers. +- `nameservers` (Attributes) Settings determining the nameservers through which the zone should be available. (see [below for nested schema](#nestedatt--zone_defaults--nameservers)) +- `ns_ttl` (Number) The time to live (TTL) of the zone's nameserver (NS) records. +- `secondary_overrides` (Boolean) Allows a Secondary DNS zone to use (proxied) override records and CNAME flattening at the zone apex. +- `soa` (Attributes) Components of the zone's SOA record. (see [below for nested schema](#nestedatt--zone_defaults--soa)) +- `zone_mode` (String) Whether the zone mode is a regular or CDN/DNS only zone. + + +### Nested Schema for `zone_defaults.internal_dns` + +Optional: + +- `reference_zone_id` (String) The ID of the zone to fallback to. + + + +### Nested Schema for `zone_defaults.nameservers` + +Required: + +- `type` (String) Nameserver type + + + +### Nested Schema for `zone_defaults.soa` + +Required: + +- `expire` (Number) Time in seconds of being unable to query the primary server after which secondary servers should stop serving the zone. +- `min_ttl` (Number) The time to live (TTL) for negative caching of records within the zone. +- `mname` (String) The primary nameserver, which may be used for outbound zone transfers. +- `refresh` (Number) Time in seconds after which secondary servers should re-check the SOA record to see if the zone has been updated. +- `retry` (Number) Time in seconds after which secondary servers should retry queries after the primary server was unresponsive. +- `rname` (String) The email address of the zone administrator, with the first label representing the local part of the email address. +- `ttl` (Number) The time to live (TTL) of the SOA record itself. + + diff --git a/docs/resources/dns_settings_internal_view.md b/docs/resources/dns_settings_internal_view.md new file mode 100644 index 0000000000..a197beaf2b --- /dev/null +++ b/docs/resources/dns_settings_internal_view.md @@ -0,0 +1,43 @@ +--- +page_title: "cloudflare_dns_settings_internal_view Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_dns_settings_internal_view (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_dns_settings_internal_view" "example_dns_settings_internal_view" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + name = "my view" + zones = ["372e67954025e0ba6aaa6d586b9e0b59"] +} +``` + + +## Schema + +### Required + +- `account_id` (String) Identifier +- `name` (String) The name of the view. +- `zones` (List of String) The list of zones linked to this view. + +### Read-Only + +- `created_time` (String) When the view was created. +- `id` (String) Identifier +- `modified_time` (String) When the view was last modified. + +## Import + +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_dns_settings_internal_view.example '/' +``` diff --git a/docs/resources/email_security_block_sender.md b/docs/resources/email_security_block_sender.md index 4d09d92a85..756274db66 100644 --- a/docs/resources/email_security_block_sender.md +++ b/docs/resources/email_security_block_sender.md @@ -14,10 +14,10 @@ description: |- ```terraform resource "cloudflare_email_security_block_sender" "example_email_security_block_sender" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" - is_regex = false - pattern = "test@example.com" + is_regex = true + pattern = "x" pattern_type = "EMAIL" - comments = "block sender with email test@example.com" + comments = "comments" } ``` diff --git a/docs/resources/email_security_trusted_domains.md b/docs/resources/email_security_trusted_domains.md index 7b5b9123e7..2096b7e5c8 100644 --- a/docs/resources/email_security_trusted_domains.md +++ b/docs/resources/email_security_trusted_domains.md @@ -15,10 +15,10 @@ description: |- resource "cloudflare_email_security_trusted_domains" "example_email_security_trusted_domains" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" is_recent = true - is_regex = false - is_similarity = false - pattern = "example.com" - comments = null + is_regex = true + is_similarity = true + pattern = "x" + comments = "comments" } ``` diff --git a/docs/resources/filter.md b/docs/resources/filter.md index dabb5b2a29..5c742fa964 100644 --- a/docs/resources/filter.md +++ b/docs/resources/filter.md @@ -32,10 +32,6 @@ resource "cloudflare_filter" "example_filter" { - `expression` (String) The filter expression. For more information, refer to [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/). - `zone_id` (String) Identifier -### Optional - -- `filter_id` (String) The unique identifier of the filter. - ### Read-Only - `description` (String) An informative summary of the filter. @@ -43,4 +39,10 @@ resource "cloudflare_filter" "example_filter" { - `paused` (Boolean) When true, indicates that the filter is currently paused. - `ref` (String) A short reference tag. Allows you to select related filters. +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_filter.example '/' +``` diff --git a/docs/resources/firewall_rule.md b/docs/resources/firewall_rule.md index b5b974a271..e5fb116ef5 100644 --- a/docs/resources/firewall_rule.md +++ b/docs/resources/firewall_rule.md @@ -45,10 +45,6 @@ resource "cloudflare_firewall_rule" "example_firewall_rule" { - `filter` (Attributes) (see [below for nested schema](#nestedatt--filter)) - `zone_id` (String) Identifier -### Optional - -- `rule_id` (String) The unique identifier of the firewall rule. - ### Read-Only - `description` (String) An informative summary of the firewall rule. @@ -93,4 +89,10 @@ Read-Only: - `id` (String) The unique identifier of the filter. +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_firewall_rule.example '/' +``` diff --git a/docs/resources/hostname_tls_setting.md b/docs/resources/hostname_tls_setting.md index 596b1ed8c0..5b6459e4e3 100644 --- a/docs/resources/hostname_tls_setting.md +++ b/docs/resources/hostname_tls_setting.md @@ -26,7 +26,7 @@ resource "cloudflare_hostname_tls_setting" "example_hostname_tls_setting" { ### Required - `setting_id` (String) The TLS Setting name. -- `value` (Number) The tls setting value. +- `value` (Dynamic) The tls setting value. - `zone_id` (String) Identifier ### Optional diff --git a/docs/resources/list.md b/docs/resources/list.md index 16cc05abc3..e093fbc677 100644 --- a/docs/resources/list.md +++ b/docs/resources/list.md @@ -9,12 +9,6 @@ description: |- -~> The `cloudflare_list` resource supports defining list items in line with the - `item` attribute. The provider also has a `cloudflare_list_item` resource for - managing items as independent resources. Using both in line `item` definitions - _and_ `cloudflare_list_items` on the same list is not supported and will cause - Terraform into an irreconcilable state. - ## Example Usage ```terraform @@ -25,6 +19,7 @@ resource "cloudflare_list" "example_list" { description = "This is a note" } ``` + ## Schema diff --git a/docs/resources/list_item.md b/docs/resources/list_item.md index 2113defd9c..8f6021558c 100644 --- a/docs/resources/list_item.md +++ b/docs/resources/list_item.md @@ -46,16 +46,15 @@ resource "cloudflare_list_item" "example_list_item" { - `account_id` (String) Identifier - `asn` (Number) A non-negative 32 bit integer +- `comment` (String) An informative summary of the list item. - `hostname` (Attributes) Valid characters for hostnames are ASCII(7) letters from a to z, the digits from 0 to 9, wildcards (*), and the hyphen (-). (see [below for nested schema](#nestedatt--hostname)) - `ip` (String) An IPv4 address, an IPv4 CIDR, or an IPv6 CIDR. IPv6 CIDRs are limited to a maximum of /64. - `redirect` (Attributes) The definition of the redirect. (see [below for nested schema](#nestedatt--redirect)) ### Read-Only -- `comment` (String) An informative summary of the list item. - `created_on` (String) The RFC 3339 timestamp of when the item was created. -- `id` (String) The unique ID of the list. -- `item_id` (String) The unique ID of the item in the List. +- `id` (String) The unique ID of the item in the List. - `modified_on` (String) The RFC 3339 timestamp of when the item was last modified. - `operation_id` (String) The unique operation ID of the asynchronous action. diff --git a/docs/resources/magic_firewall_ruleset.md b/docs/resources/magic_firewall_ruleset.md deleted file mode 100644 index 7b2cf4510d..0000000000 --- a/docs/resources/magic_firewall_ruleset.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -layout: "cloudflare" -page_title: "Cloudflare: cloudflare_magic_firewall_ruleset" -description: Provides the ability to manage a Magic Firewall Ruleset and it's firewall rules which are used with Magic Transit. ---- - -# cloudflare_magic_firewall_ruleset - -Magic Firewall is a network-level firewall to protect networks that are onboarded to Cloudflare's Magic Transit. This resource -creates a root ruleset on the account level and contains one or more rules. Rules can be crafted in Wireshark syntax and -are evaluated in order, with the first rule having the highest priority. - -## Example Usage - -```hcl -resource "cloudflare_magic_firewall_ruleset" "example" { - account_id = "d41d8cd98f00b204e9800998ecf8427e" - name = "Magic Transit Ruleset" - description = "Global mitigations" - - rules = [ - { - action = "allow" - expression = "tcp.dstport in { 32768..65535 }" - description = "Allow TCP Ephemeral Ports" - enabled = "true" - }, - { - action = "block" - expression = "ip.len >= 0" - description = "Block all" - enabled = "true" - } - ] -} -``` - -## Argument Reference - -The following arguments are supported: - -- `account_id` - (Required) The ID of the account where the ruleset is being created. -- `name` - (Required) The name of the ruleset. -- `description` - (Optional) A note that can be used to annotate the ruleset. - -The **rules** block is a list of maps with the following attributes: - -- `action` - (Required) Valid values: `allow` or `block`. -- `expression` - (Required) A Firewall expression using Wireshark syntax. -- `description` - (Optional) A note that can be used to annotate the rule. -- `enabled` - (Required) Whether the rule is enabled or not. Valid values: `true` or `false`. - -## Import - -An existing Magic Firewall Ruleset can be imported using the account ID and ruleset ID - -``` -$ terraform import cloudflare_magic_firewall_ruleset.example d41d8cd98f00b204e9800998ecf8427e/cb029e245cfdd66dc8d2e570d5dd3322 -``` diff --git a/docs/resources/magic_transit_site_lan.md b/docs/resources/magic_transit_site_lan.md index 5fb9e80125..45dffc0f6e 100644 --- a/docs/resources/magic_transit_site_lan.md +++ b/docs/resources/magic_transit_site_lan.md @@ -38,6 +38,7 @@ resource "cloudflare_magic_transit_site_lan" "example_magic_transit_site_lan" { dhcp_pool_end = "192.0.2.1" dhcp_pool_start = "192.0.2.1" dns_server = "192.0.2.1" + dns_servers = ["192.0.2.1"] reservations = { "00:11:22:33:44:55" = "192.0.2.100" "AA:BB:CC:DD:EE:FF" = "192.168.1.101" @@ -62,7 +63,6 @@ resource "cloudflare_magic_transit_site_lan" "example_magic_transit_site_lan" { ### Optional - `ha_link` (Boolean) mark true to use this LAN for HA probing. only works for site with HA turned on. only one LAN can be set as the ha_link. -- `lan_id` (String) Identifier - `name` (String) - `nat` (Attributes) (see [below for nested schema](#nestedatt--nat)) - `routed_subnets` (Attributes List) (see [below for nested schema](#nestedatt--routed_subnets)) @@ -131,6 +131,13 @@ Optional: - `dhcp_pool_end` (String) A valid IPv4 address. - `dhcp_pool_start` (String) A valid IPv4 address. - `dns_server` (String) A valid IPv4 address. +- `dns_servers` (List of String) - `reservations` (Map of String) Mapping of MAC addresses to IP addresses +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_magic_transit_site_lan.example '//' +``` diff --git a/docs/resources/magic_transit_site_wan.md b/docs/resources/magic_transit_site_wan.md index d2f94e3318..b20a3d3148 100644 --- a/docs/resources/magic_transit_site_wan.md +++ b/docs/resources/magic_transit_site_wan.md @@ -42,7 +42,6 @@ resource "cloudflare_magic_transit_site_wan" "example_magic_transit_site_wan" { - `name` (String) - `priority` (Number) - `static_addressing` (Attributes) (optional) if omitted, use DHCP. Submit secondary_address when site is in high availability mode. (see [below for nested schema](#nestedatt--static_addressing)) -- `wan_id` (String) Identifier ### Read-Only @@ -61,4 +60,10 @@ Optional: - `secondary_address` (String) A valid CIDR notation representing an IP range. +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_magic_transit_site_wan.example '//' +``` diff --git a/docs/resources/magic_wan_static_route.md b/docs/resources/magic_wan_static_route.md index 0e60485d44..a05bf90f37 100644 --- a/docs/resources/magic_wan_static_route.md +++ b/docs/resources/magic_wan_static_route.md @@ -30,7 +30,9 @@ resource "cloudflare_magic_wan_static_route" "example_magic_wan_static_route" { - `nexthop` (String) The next-hop IP Address for the static route. - `prefix` (String) IP Prefix in Classless Inter-Domain Routing format. - `priority` (Number) Priority of the static route. +- `route` (Attributes) (see [below for nested schema](#nestedatt--route)) - `route_id` (String) Identifier +- `routes` (Attributes List) (see [below for nested schema](#nestedatt--routes)) - `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--scope)) - `weight` (Number) Optional weight of the ECMP scope - if provided. @@ -38,70 +40,74 @@ resource "cloudflare_magic_wan_static_route" "example_magic_wan_static_route" { - `modified` (Boolean) - `modified_route` (Attributes) (see [below for nested schema](#nestedatt--modified_route)) -- `route` (Attributes) (see [below for nested schema](#nestedatt--route)) -- `routes` (Attributes List) (see [below for nested schema](#nestedatt--routes)) - -### Nested Schema for `scope` + +### Nested Schema for `route` Optional: -- `colo_names` (List of String) List of colo names for the ECMP scope. -- `colo_regions` (List of String) List of colo regions for the ECMP scope. - - - -### Nested Schema for `modified_route` +- `description` (String) An optional human provided description of the static route. +- `nexthop` (String) The next-hop IP Address for the static route. +- `prefix` (String) IP Prefix in Classless Inter-Domain Routing format. +- `priority` (Number) Priority of the static route. +- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--route--scope)) +- `weight` (Number) Optional weight of the ECMP scope - if provided. Read-Only: - `created_on` (String) When the route was created. -- `description` (String) An optional human provided description of the static route. - `id` (String) Identifier - `modified_on` (String) When the route was last modified. -- `nexthop` (String) The next-hop IP Address for the static route. -- `prefix` (String) IP Prefix in Classless Inter-Domain Routing format. -- `priority` (Number) Priority of the static route. -- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--modified_route--scope)) -- `weight` (Number) Optional weight of the ECMP scope - if provided. - -### Nested Schema for `modified_route.scope` + +### Nested Schema for `route.scope` -Read-Only: +Optional: - `colo_names` (List of String) List of colo names for the ECMP scope. - `colo_regions` (List of String) List of colo regions for the ECMP scope. - -### Nested Schema for `route` + +### Nested Schema for `routes` -Read-Only: +Optional: -- `created_on` (String) When the route was created. - `description` (String) An optional human provided description of the static route. -- `id` (String) Identifier -- `modified_on` (String) When the route was last modified. - `nexthop` (String) The next-hop IP Address for the static route. - `prefix` (String) IP Prefix in Classless Inter-Domain Routing format. - `priority` (Number) Priority of the static route. -- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--route--scope)) +- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--routes--scope)) - `weight` (Number) Optional weight of the ECMP scope - if provided. - -### Nested Schema for `route.scope` - Read-Only: +- `created_on` (String) When the route was created. +- `id` (String) Identifier +- `modified_on` (String) When the route was last modified. + + +### Nested Schema for `routes.scope` + +Optional: + - `colo_names` (List of String) List of colo names for the ECMP scope. - `colo_regions` (List of String) List of colo regions for the ECMP scope. - -### Nested Schema for `routes` + +### Nested Schema for `scope` + +Optional: + +- `colo_names` (List of String) List of colo names for the ECMP scope. +- `colo_regions` (List of String) List of colo regions for the ECMP scope. + + + +### Nested Schema for `modified_route` Read-Only: @@ -112,11 +118,11 @@ Read-Only: - `nexthop` (String) The next-hop IP Address for the static route. - `prefix` (String) IP Prefix in Classless Inter-Domain Routing format. - `priority` (Number) Priority of the static route. -- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--routes--scope)) +- `scope` (Attributes) Used only for ECMP routes. (see [below for nested schema](#nestedatt--modified_route--scope)) - `weight` (Number) Optional weight of the ECMP scope - if provided. - -### Nested Schema for `routes.scope` + +### Nested Schema for `modified_route.scope` Read-Only: diff --git a/docs/resources/origin_ca_certificate.md b/docs/resources/origin_ca_certificate.md index eaecadd729..0fe81e88a4 100644 --- a/docs/resources/origin_ca_certificate.md +++ b/docs/resources/origin_ca_certificate.md @@ -9,10 +9,6 @@ description: |- -~> Since [v3.32.0](https://github.com/cloudflare/terraform-provider-cloudflare/releases/tag/v3.32.0) - all authentication schemes are supported for managing Origin CA certificates. - Versions prior to v3.32.0 will still need to use [`api_user_service_key`](../index.html#api_user_service_key). - ## Example Usage ```terraform @@ -41,6 +37,7 @@ resource "cloudflare_origin_ca_certificate" "example_origin_ca_certificate" { requested_validity = 7 } ``` + ## Schema diff --git a/docs/resources/pages_domain.md b/docs/resources/pages_domain.md index bce883f7cd..b4167a3361 100644 --- a/docs/resources/pages_domain.md +++ b/docs/resources/pages_domain.md @@ -27,11 +27,8 @@ resource "cloudflare_pages_domain" "example_pages_domain" { ### Required - `account_id` (String) Identifier -- `project_name` (String) Name of the project. - -### Optional - - `name` (String) +- `project_name` (String) Name of the project. ### Read-Only diff --git a/docs/resources/r2_bucket.md b/docs/resources/r2_bucket.md index d43dac370a..a9c5187a80 100644 --- a/docs/resources/r2_bucket.md +++ b/docs/resources/r2_bucket.md @@ -7,6 +7,8 @@ description: |- # cloudflare_r2_bucket (Resource) + + ## Example Usage ```terraform @@ -18,8 +20,6 @@ resource "cloudflare_r2_bucket" "example_r2_bucket" { } ``` --> Available location values can be found in the [R2 documentation](https://developers.cloudflare.com/r2/reference/data-location/#available-hints). - ## Schema @@ -44,5 +44,5 @@ resource "cloudflare_r2_bucket" "example_r2_bucket" { Import is supported using the following syntax: ```shell -$ terraform import cloudflare_r2_bucket.example '/' +$ terraform import cloudflare_r2_bucket.example '//' ``` diff --git a/docs/resources/r2_bucket_cors.md b/docs/resources/r2_bucket_cors.md new file mode 100644 index 0000000000..264bef2b64 --- /dev/null +++ b/docs/resources/r2_bucket_cors.md @@ -0,0 +1,68 @@ +--- +page_title: "cloudflare_r2_bucket_cors Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_cors (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_bucket_cors" "example_r2_bucket_cors" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + allowed = { + methods = ["GET"] + origins = ["http://localhost:3000"] + headers = ["x-requested-by"] + } + id = "Allow Local Development" + expose_headers = ["Content-Encoding"] + max_age_seconds = 3600 + }] +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Optional + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Required: + +- `allowed` (Attributes) Object specifying allowed origins, methods and headers for this CORS rule. (see [below for nested schema](#nestedatt--rules--allowed)) + +Optional: + +- `expose_headers` (List of String) Specifies the headers that can be exposed back, and accessed by, the JavaScript making the cross-origin request. If you need to access headers beyond the safelisted response headers, such as Content-Encoding or cf-cache-status, you must specify it here. +- `id` (String) Identifier for this rule +- `max_age_seconds` (Number) Specifies the amount of time (in seconds) browsers are allowed to cache CORS preflight responses. Browsers may limit this to 2 hours or less, even if the maximum value (86400) is specified. + + +### Nested Schema for `rules.allowed` + +Required: + +- `methods` (List of String) Specifies the value for the Access-Control-Allow-Methods header R2 sets when requesting objects in a bucket from a browser. +- `origins` (List of String) Specifies the value for the Access-Control-Allow-Origin header R2 sets when requesting objects in a bucket from a browser. + +Optional: + +- `headers` (List of String) Specifies the value for the Access-Control-Allow-Headers header R2 sets when requesting objects in this bucket from a browser. Cross-origin requests that include custom headers (e.g. x-user-id) should specify these headers as AllowedHeaders. + + diff --git a/docs/resources/r2_bucket_event_notification.md b/docs/resources/r2_bucket_event_notification.md new file mode 100644 index 0000000000..38d8507a1a --- /dev/null +++ b/docs/resources/r2_bucket_event_notification.md @@ -0,0 +1,80 @@ +--- +page_title: "cloudflare_r2_bucket_event_notification Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_event_notification (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_bucket_event_notification" "example_r2_bucket_event_notification" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + queue_id = "queue_id" + rules = [{ + actions = ["PutObject", "CopyObject"] + description = "Notifications from source bucket to queue" + prefix = "img/" + suffix = ".jpeg" + }] +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Optional + +- `queue_id` (String) Queue ID +- `rules` (Attributes List) Array of rules to drive notifications (see [below for nested schema](#nestedatt--rules)) + +### Read-Only + +- `queues` (Attributes List) List of queues associated with the bucket. (see [below for nested schema](#nestedatt--queues)) + + +### Nested Schema for `rules` + +Required: + +- `actions` (List of String) Array of R2 object actions that will trigger notifications + +Optional: + +- `description` (String) A description that can be used to identify the event notification rule after creation +- `prefix` (String) Notifications will be sent only for objects with this prefix +- `suffix` (String) Notifications will be sent only for objects with this suffix + + + +### Nested Schema for `queues` + +Read-Only: + +- `queue_id` (String) Queue ID +- `queue_name` (String) Name of the queue +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--queues--rules)) + + +### Nested Schema for `queues.rules` + +Read-Only: + +- `actions` (List of String) Array of R2 object actions that will trigger notifications +- `created_at` (String) Timestamp when the rule was created +- `description` (String) A description that can be used to identify the event notification rule after creation +- `prefix` (String) Notifications will be sent only for objects with this prefix +- `rule_id` (String) Rule ID +- `suffix` (String) Notifications will be sent only for objects with this suffix + + diff --git a/docs/resources/r2_bucket_lifecycle.md b/docs/resources/r2_bucket_lifecycle.md new file mode 100644 index 0000000000..063a18f603 --- /dev/null +++ b/docs/resources/r2_bucket_lifecycle.md @@ -0,0 +1,140 @@ +--- +page_title: "cloudflare_r2_bucket_lifecycle Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_lifecycle (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_bucket_lifecycle" "example_r2_bucket_lifecycle" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + id = "Expire all objects older than 24 hours" + conditions = { + prefix = "prefix" + } + enabled = true + abort_multipart_uploads_transition = { + condition = { + max_age = 0 + type = "Age" + } + } + delete_objects_transition = { + condition = { + max_age = 0 + type = "Age" + } + } + storage_class_transitions = [{ + condition = { + max_age = 0 + type = "Age" + } + storage_class = "InfrequentAccess" + }] + }] +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Optional + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Required: + +- `conditions` (Attributes) Conditions that apply to all transitions of this rule (see [below for nested schema](#nestedatt--rules--conditions)) +- `enabled` (Boolean) Whether or not this rule is in effect +- `id` (String) Unique identifier for this rule + +Optional: + +- `abort_multipart_uploads_transition` (Attributes) Transition to abort ongoing multipart uploads (see [below for nested schema](#nestedatt--rules--abort_multipart_uploads_transition)) +- `delete_objects_transition` (Attributes) Transition to delete objects (see [below for nested schema](#nestedatt--rules--delete_objects_transition)) +- `storage_class_transitions` (Attributes List) Transitions to change the storage class of objects (see [below for nested schema](#nestedatt--rules--storage_class_transitions)) + + +### Nested Schema for `rules.conditions` + +Required: + +- `prefix` (String) Transitions will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads + + + +### Nested Schema for `rules.abort_multipart_uploads_transition` + +Optional: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--abort_multipart_uploads_transition--condition)) + + +### Nested Schema for `rules.abort_multipart_uploads_transition.condition` + +Required: + +- `max_age` (Number) +- `type` (String) + + + + +### Nested Schema for `rules.delete_objects_transition` + +Optional: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--delete_objects_transition--condition)) + + +### Nested Schema for `rules.delete_objects_transition.condition` + +Required: + +- `type` (String) + +Optional: + +- `date` (String) +- `max_age` (Number) + + + + +### Nested Schema for `rules.storage_class_transitions` + +Required: + +- `condition` (Attributes) Condition for lifecycle transitions to apply after an object reaches an age in seconds (see [below for nested schema](#nestedatt--rules--storage_class_transitions--condition)) +- `storage_class` (String) + + +### Nested Schema for `rules.storage_class_transitions.condition` + +Required: + +- `type` (String) + +Optional: + +- `date` (String) +- `max_age` (Number) + + diff --git a/docs/resources/r2_bucket_lock.md b/docs/resources/r2_bucket_lock.md new file mode 100644 index 0000000000..fdfbdeaaed --- /dev/null +++ b/docs/resources/r2_bucket_lock.md @@ -0,0 +1,67 @@ +--- +page_title: "cloudflare_r2_bucket_lock Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_lock (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_bucket_lock" "example_r2_bucket_lock" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + id = "Lock all objects for 24 hours" + condition = { + max_age_seconds = 100 + type = "Age" + } + enabled = true + prefix = "prefix" + }] +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Optional + +- `rules` (Attributes List) (see [below for nested schema](#nestedatt--rules)) + + +### Nested Schema for `rules` + +Required: + +- `condition` (Attributes) Condition to apply a lock rule to an object for how long in seconds (see [below for nested schema](#nestedatt--rules--condition)) +- `enabled` (Boolean) Whether or not this rule is in effect +- `id` (String) Unique identifier for this rule + +Optional: + +- `prefix` (String) Rule will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads + + +### Nested Schema for `rules.condition` + +Required: + +- `type` (String) + +Optional: + +- `date` (String) +- `max_age_seconds` (Number) + + diff --git a/docs/resources/r2_bucket_sippy.md b/docs/resources/r2_bucket_sippy.md new file mode 100644 index 0000000000..d7e5439f15 --- /dev/null +++ b/docs/resources/r2_bucket_sippy.md @@ -0,0 +1,83 @@ +--- +page_title: "cloudflare_r2_bucket_sippy Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_bucket_sippy (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_bucket_sippy" "example_r2_bucket_sippy" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + destination = { + access_key_id = "accessKeyId" + provider = "r2" + secret_access_key = "secretAccessKey" + } + source = { + access_key_id = "accessKeyId" + bucket = "bucket" + provider = "aws" + region = "region" + secret_access_key = "secretAccessKey" + } +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket + +### Optional + +- `destination` (Attributes) R2 bucket to copy objects to (see [below for nested schema](#nestedatt--destination)) +- `source` (Attributes) AWS S3 bucket to copy objects from (see [below for nested schema](#nestedatt--source)) + +### Read-Only + +- `enabled` (Boolean) State of Sippy for this bucket + + +### Nested Schema for `destination` + +Optional: + +- `access_key_id` (String) ID of a Cloudflare API token. +This is the value labelled "Access Key ID" when creating an API +token from the [R2 dashboard](https://dash.cloudflare.com/?to=/:account/r2/api-tokens). + +Sippy will use this token when writing objects to R2, so it is +best to scope this token to the bucket you're enabling Sippy for. +- `provider` (String) +- `secret_access_key` (String) Value of a Cloudflare API token. +This is the value labelled "Secret Access Key" when creating an API +token from the [R2 dashboard](https://dash.cloudflare.com/?to=/:account/r2/api-tokens). + +Sippy will use this token when writing objects to R2, so it is +best to scope this token to the bucket you're enabling Sippy for. + + + +### Nested Schema for `source` + +Optional: + +- `access_key_id` (String) Access Key ID of an IAM credential (ideally scoped to a single S3 bucket) +- `bucket` (String) Name of the AWS S3 bucket +- `client_email` (String) Client email of an IAM credential (ideally scoped to a single GCS bucket) +- `private_key` (String) Private Key of an IAM credential (ideally scoped to a single GCS bucket) +- `provider` (String) +- `region` (String) Name of the AWS availability zone +- `secret_access_key` (String) Secret Access Key of an IAM credential (ideally scoped to a single S3 bucket) + + diff --git a/docs/resources/r2_custom_domain.md b/docs/resources/r2_custom_domain.md new file mode 100644 index 0000000000..814342a2d6 --- /dev/null +++ b/docs/resources/r2_custom_domain.md @@ -0,0 +1,54 @@ +--- +page_title: "cloudflare_r2_custom_domain Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_custom_domain (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_custom_domain" "example_r2_custom_domain" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + domain = "domain" + enabled = true + zone_id = "zoneId" + min_tls = "1.0" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket +- `domain` (String) Name of the custom domain to be added +- `enabled` (Boolean) Whether to enable public bucket access at the custom domain. If undefined, the domain will be enabled. +- `zone_id` (String) Zone ID of the custom domain + +### Optional + +- `domain_name` (String) Name of the custom domain +- `min_tls` (String) Minimum TLS Version the custom domain will accept for incoming connections. If not set, defaults to 1.0. + +### Read-Only + +- `status` (Attributes) (see [below for nested schema](#nestedatt--status)) +- `zone_name` (String) Zone that the custom domain resides in + + +### Nested Schema for `status` + +Read-Only: + +- `ownership` (String) Ownership status of the domain +- `ssl` (String) SSL certificate status + + diff --git a/docs/resources/r2_managed_domain.md b/docs/resources/r2_managed_domain.md new file mode 100644 index 0000000000..64181f0415 --- /dev/null +++ b/docs/resources/r2_managed_domain.md @@ -0,0 +1,36 @@ +--- +page_title: "cloudflare_r2_managed_domain Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_r2_managed_domain (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_r2_managed_domain" "example_r2_managed_domain" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + enabled = true +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account ID +- `bucket_name` (String) Name of the bucket +- `enabled` (Boolean) Whether to enable public bucket access at the r2.dev domain + +### Read-Only + +- `bucket_id` (String) Bucket ID +- `domain` (String) Domain name of the bucket's r2.dev domain + + diff --git a/docs/resources/ruleset.md b/docs/resources/ruleset.md index ad535dc778..37b9102c41 100644 --- a/docs/resources/ruleset.md +++ b/docs/resources/ruleset.md @@ -280,9 +280,6 @@ Optional: Required: - `eligible` (Boolean) Determines whether cache reserve is enabled. If this is true and a request meets eligibility criteria, Cloudflare will write the resource to cache reserve. - -Optional: - - `minimum_file_size` (Number) The minimum file size eligible for store in cache reserve. @@ -360,10 +357,13 @@ Optional: ### Nested Schema for `rules.action_parameters.headers` +Required: + +- `operation` (String) + Optional: - `expression` (String) Expression for the header value. -- `operation` (String) - `value` (String) Static value for the header. diff --git a/docs/resources/snippet_rules.md b/docs/resources/snippet_rules.md index 4cf0fb2987..de7fc5240a 100644 --- a/docs/resources/snippet_rules.md +++ b/docs/resources/snippet_rules.md @@ -34,6 +34,13 @@ resource "cloudflare_snippet_rules" "example_snippet_rules" { - `rules` (Attributes List) List of snippet rules (see [below for nested schema](#nestedatt--rules)) +### Read-Only + +- `description` (String) +- `enabled` (Boolean) +- `expression` (String) +- `snippet_name` (String) Snippet identifying name + ### Nested Schema for `rules` diff --git a/docs/resources/spectrum_application.md b/docs/resources/spectrum_application.md index b6bcb4603a..88d4ebcf6a 100644 --- a/docs/resources/spectrum_application.md +++ b/docs/resources/spectrum_application.md @@ -44,9 +44,8 @@ resource "cloudflare_spectrum_application" "example_spectrum_application" { ### Required - `dns` (Attributes) The name and type of DNS record for the Spectrum application. (see [below for nested schema](#nestedatt--dns)) -- `id` (String) Identifier - `protocol` (String) The port configuration at Cloudflare's edge. May specify a single port, for example `"tcp/1000"`, or a range of ports, for example `"tcp/1000-2000"`. -- `zone_id` (String) Identifier +- `zone_id` (String) Zone identifier. ### Optional @@ -66,6 +65,7 @@ Notes: If specifying a port range, the number of ports in the range must match t ### Read-Only - `created_on` (String) When the Application was created. +- `id` (String) App identifier. - `modified_on` (String) When the Application was last modified. diff --git a/docs/resources/waiting_room_rules.md b/docs/resources/waiting_room_rules.md index 2ec927fbd6..b0110f2e0a 100644 --- a/docs/resources/waiting_room_rules.md +++ b/docs/resources/waiting_room_rules.md @@ -33,9 +33,15 @@ resource "cloudflare_waiting_room_rules" "example_waiting_room_rules" { - `waiting_room_id` (String) - `zone_id` (String) Identifier -### Optional +### Read-Only -- `rule_id` (String) The ID of the rule. +- `action` (String) The action to take when the expression matches. +- `description` (String) The description of the rule. +- `enabled` (Boolean) When set to true, the rule is enabled. +- `expression` (String) Criteria defining when there is a match for the current rule. +- `id` (String) The ID of the rule. +- `last_updated` (String) +- `version` (String) The version of the rule. ### Nested Schema for `rules` @@ -50,4 +56,10 @@ Optional: - `description` (String) The description of the rule. - `enabled` (Boolean) When set to true, the rule is enabled. +## Import + +Import is supported using the following syntax: +```shell +$ terraform import cloudflare_waiting_room_rules.example '/' +``` diff --git a/docs/resources/workers_route.md b/docs/resources/workers_route.md new file mode 100644 index 0000000000..4c363ce27e --- /dev/null +++ b/docs/resources/workers_route.md @@ -0,0 +1,59 @@ +--- +page_title: "cloudflare_workers_route Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_workers_route (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_workers_route" "example_workers_route" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" + pattern = "example.net/*" + script = "this-is_my_script-01" +} +``` + + +## Schema + +### Required + +- `pattern` (String) +- `zone_id` (String) Identifier + +### Optional + +- `route_id` (String) Identifier +- `script` (String) Name of the script, used in URLs and route configuration. + +### Read-Only + +- `errors` (Attributes List) (see [below for nested schema](#nestedatt--errors)) +- `id` (String) Identifier +- `messages` (Attributes List) (see [below for nested schema](#nestedatt--messages)) +- `success` (Boolean) Whether the API call was successful + + +### Nested Schema for `errors` + +Read-Only: + +- `code` (Number) +- `message` (String) + + + +### Nested Schema for `messages` + +Read-Only: + +- `code` (Number) +- `message` (String) + + diff --git a/docs/resources/workers_script.md b/docs/resources/workers_script.md index f8635feada..40ac7679f4 100644 --- a/docs/resources/workers_script.md +++ b/docs/resources/workers_script.md @@ -15,58 +15,57 @@ description: |- resource "cloudflare_workers_script" "example_workers_script" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" script_name = "this-is_my_script-01" - metadata = { - assets = { - config = { - html_handling = "auto-trailing-slash" - not_found_handling = "none" - run_worker_first = false - serve_directly = true - } - jwt = "jwt" + assets = { + config = { + html_handling = "auto-trailing-slash" + not_found_handling = "none" + run_worker_first = false + serve_directly = true } - bindings = [{ - name = "MY_ENV_VAR" - type = "plain_text" + jwt = "jwt" + } + bindings = [{ + name = "MY_ENV_VAR" + text = "my_data" + type = "plain_text" + }] + body_part = "worker.js" + compatibility_date = "2021-01-01" + compatibility_flags = ["nodejs_compat"] + keep_assets = false + keep_bindings = ["string"] + logpush = false + main_module = "worker.js" + migrations = { + deleted_classes = ["string"] + new_classes = ["string"] + new_sqlite_classes = ["string"] + new_tag = "v2" + old_tag = "v1" + renamed_classes = [{ + from = "from" + to = "to" }] - body_part = "worker.js" - compatibility_date = "2021-01-01" - compatibility_flags = ["nodejs_compat"] - keep_assets = false - keep_bindings = ["string"] - logpush = false - main_module = "worker.js" - migrations = { - deleted_classes = ["string"] - new_classes = ["string"] - new_sqlite_classes = ["string"] - new_tag = "v2" - old_tag = "v1" - renamed_classes = [{ - from = "from" - to = "to" - }] - transferred_classes = [{ - from = "from" - from_script = "from_script" - to = "to" - }] - } - observability = { - enabled = true - head_sampling_rate = 0.1 - } - placement = { - mode = "smart" - } - tags = ["string"] - tail_consumers = [{ - service = "my-log-consumer" - environment = "production" - namespace = "my-namespace" + transferred_classes = [{ + from = "from" + from_script = "from_script" + to = "to" }] - usage_model = "standard" } + observability = { + enabled = true + head_sampling_rate = 0.1 + } + placement = { + mode = "smart" + } + tags = ["string"] + tail_consumers = [{ + service = "my-log-consumer" + environment = "production" + namespace = "my-namespace" + }] + usage_model = "standard" } ``` diff --git a/docs/resources/zero_trust_access_application.md b/docs/resources/zero_trust_access_application.md index 61214bc027..5db59da159 100644 --- a/docs/resources/zero_trust_access_application.md +++ b/docs/resources/zero_trust_access_application.md @@ -260,6 +260,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--exclude--service_token)) @@ -406,6 +407,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.exclude.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.exclude.okta` @@ -457,6 +466,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--include--service_token)) @@ -603,6 +613,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.include.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.include.okta` @@ -654,6 +672,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--policies--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--policies--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--policies--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--policies--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--policies--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--policies--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--policies--require--service_token)) @@ -800,6 +819,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `policies.require.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `policies.require.okta` @@ -880,7 +907,16 @@ Optional: Optional: - `name` (String) The name of the IdP attribute. -- `name_by_idp` (Map of String) A mapping from IdP ID to attribute name. +- `name_by_idp` (Attributes List) A mapping from IdP ID to attribute name. (see [below for nested schema](#nestedatt--saas_app--custom_attributes--source--name_by_idp)) + + +### Nested Schema for `saas_app.custom_attributes.source.name_by_idp` + +Optional: + +- `idp_id` (String) The UID of the IdP. +- `source_name` (String) The name of the IdP provided attribute. + diff --git a/docs/resources/zero_trust_access_group.md b/docs/resources/zero_trust_access_group.md index 698347e123..e209b995ee 100644 --- a/docs/resources/zero_trust_access_group.md +++ b/docs/resources/zero_trust_access_group.md @@ -79,6 +79,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--include--service_token)) @@ -225,6 +226,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `include.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `include.okta` @@ -276,6 +285,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--exclude--service_token)) @@ -422,6 +432,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `exclude.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `exclude.okta` @@ -473,6 +491,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--require--service_token)) @@ -619,6 +638,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `require.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `require.okta` diff --git a/docs/resources/zero_trust_access_mtls_hostname_settings.md b/docs/resources/zero_trust_access_mtls_hostname_settings.md index fca39f618a..a999072028 100644 --- a/docs/resources/zero_trust_access_mtls_hostname_settings.md +++ b/docs/resources/zero_trust_access_mtls_hostname_settings.md @@ -34,6 +34,12 @@ resource "cloudflare_zero_trust_access_mtls_hostname_settings" "example_zero_tru - `account_id` (String) The Account ID to use for this endpoint. Mutually exclusive with the Zone ID. - `zone_id` (String) The Zone ID to use for this endpoint. Mutually exclusive with the Account ID. +### Read-Only + +- `china_network` (Boolean) Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled. +- `client_certificate_forwarding` (Boolean) Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin. +- `hostname` (String) The hostname that these settings apply to. + ### Nested Schema for `settings` diff --git a/docs/resources/zero_trust_access_policy.md b/docs/resources/zero_trust_access_policy.md index f7c8648203..ad9f4af6a4 100644 --- a/docs/resources/zero_trust_access_policy.md +++ b/docs/resources/zero_trust_access_policy.md @@ -104,6 +104,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--include--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--include--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--include--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--include--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--include--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--include--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--include--service_token)) @@ -250,6 +251,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `include.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `include.okta` @@ -314,6 +323,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--exclude--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--exclude--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--exclude--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--exclude--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--exclude--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--exclude--service_token)) @@ -460,6 +470,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `exclude.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `exclude.okta` @@ -511,6 +529,7 @@ Optional: - `gsuite` (Attributes) (see [below for nested schema](#nestedatt--require--gsuite)) - `ip` (Attributes) (see [below for nested schema](#nestedatt--require--ip)) - `ip_list` (Attributes) (see [below for nested schema](#nestedatt--require--ip_list)) +- `login_method` (Attributes) (see [below for nested schema](#nestedatt--require--login_method)) - `okta` (Attributes) (see [below for nested schema](#nestedatt--require--okta)) - `saml` (Attributes) (see [below for nested schema](#nestedatt--require--saml)) - `service_token` (Attributes) (see [below for nested schema](#nestedatt--require--service_token)) @@ -657,6 +676,14 @@ Required: - `id` (String) The ID of a previously created IP list. + +### Nested Schema for `require.login_method` + +Required: + +- `id` (String) The ID of an identity provider. + + ### Nested Schema for `require.okta` diff --git a/docs/resources/zero_trust_device_custom_profile_local_domain_fallback.md b/docs/resources/zero_trust_device_custom_profile_local_domain_fallback.md index 75bc45607a..d08f74bdd1 100644 --- a/docs/resources/zero_trust_device_custom_profile_local_domain_fallback.md +++ b/docs/resources/zero_trust_device_custom_profile_local_domain_fallback.md @@ -34,7 +34,10 @@ resource "cloudflare_zero_trust_device_custom_profile_local_domain_fallback" "ex ### Read-Only +- `description` (String) A description of the fallback domain, displayed in the client UI. +- `dns_server` (List of String) A list of IP addresses to handle domain resolution. - `id` (String) Device ID. +- `suffix` (String) The domain suffix to match when resolving locally. ### Nested Schema for `domains` diff --git a/docs/resources/zero_trust_device_default_profile.md b/docs/resources/zero_trust_device_default_profile.md index 7555da664a..3281fdfb3e 100644 --- a/docs/resources/zero_trust_device_default_profile.md +++ b/docs/resources/zero_trust_device_default_profile.md @@ -59,6 +59,7 @@ resource "cloudflare_zero_trust_device_default_profile" "example_zero_trust_devi - `exclude` (Attributes List) (see [below for nested schema](#nestedatt--exclude)) - `fallback_domains` (Attributes List) (see [below for nested schema](#nestedatt--fallback_domains)) - `gateway_unique_id` (String) +- `id` (String) The ID of this resource. - `include` (Attributes List) (see [below for nested schema](#nestedatt--include)) @@ -99,4 +100,10 @@ Read-Only: - `description` (String) A description of the split tunnel item, displayed in the client UI. - `host` (String) The domain name to include in the tunnel. If host is present, address must not be present. +## Import +Import is supported using the following syntax: + +```shell +$ terraform import cloudflare_zero_trust_device_default_profile.example '' +``` diff --git a/docs/resources/zero_trust_device_default_profile_local_domain_fallback.md b/docs/resources/zero_trust_device_default_profile_local_domain_fallback.md index d348cef771..02360f5342 100644 --- a/docs/resources/zero_trust_device_default_profile_local_domain_fallback.md +++ b/docs/resources/zero_trust_device_default_profile_local_domain_fallback.md @@ -30,6 +30,12 @@ resource "cloudflare_zero_trust_device_default_profile_local_domain_fallback" "e - `account_id` (String) - `domains` (Attributes List) (see [below for nested schema](#nestedatt--domains)) +### Read-Only + +- `description` (String) A description of the fallback domain, displayed in the client UI. +- `dns_server` (List of String) A list of IP addresses to handle domain resolution. +- `suffix` (String) The domain suffix to match when resolving locally. + ### Nested Schema for `domains` diff --git a/docs/resources/zero_trust_device_managed_networks.md b/docs/resources/zero_trust_device_managed_networks.md index a216e0c409..19918db491 100644 --- a/docs/resources/zero_trust_device_managed_networks.md +++ b/docs/resources/zero_trust_device_managed_networks.md @@ -15,7 +15,7 @@ description: |- resource "cloudflare_zero_trust_device_managed_networks" "example_zero_trust_device_managed_networks" { account_id = "699d98642c564d2e855e9661899b7252" config = { - tls_sockaddr = "foobar:1234" + tls_sockaddr = "foo.bar:1234" sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c" } name = "managed-network-1" @@ -29,7 +29,7 @@ resource "cloudflare_zero_trust_device_managed_networks" "example_zero_trust_dev ### Required - `account_id` (String) -- `config` (Attributes) (see [below for nested schema](#nestedatt--config)) +- `config` (Attributes) The configuration object containing information for the WARP client to detect the managed network. (see [below for nested schema](#nestedatt--config)) - `name` (String) The name of the device managed network. This name must be unique. - `type` (String) The type of device managed network. diff --git a/docs/resources/zero_trust_dlp_custom_profile.md b/docs/resources/zero_trust_dlp_custom_profile.md index 846a436f16..9be9685946 100644 --- a/docs/resources/zero_trust_dlp_custom_profile.md +++ b/docs/resources/zero_trust_dlp_custom_profile.md @@ -24,6 +24,7 @@ resource "cloudflare_zero_trust_dlp_custom_profile" "example_zero_trust_dlp_cust } }] name = "name" + ai_context_enabled = true allowed_match_count = 5 confidence_threshold = "confidence_threshold" context_awareness = { @@ -52,6 +53,7 @@ resource "cloudflare_zero_trust_dlp_custom_profile" "example_zero_trust_dlp_cust ### Optional +- `ai_context_enabled` (Boolean) - `allowed_match_count` (Number) Related DLP policies will trigger when the match count exceeds the number set. - `confidence_threshold` (String) - `context_awareness` (Attributes) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedatt--context_awareness)) @@ -123,6 +125,7 @@ Required: Optional: +- `ai_context_enabled` (Boolean) - `allowed_match_count` (Number) Related DLP policies will trigger when the match count exceeds the number set. - `confidence_threshold` (String) - `context_awareness` (Attributes) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedatt--profiles--context_awareness)) diff --git a/docs/resources/zero_trust_dlp_entry.md b/docs/resources/zero_trust_dlp_entry.md index 7eb5d16961..dc1b5109fa 100644 --- a/docs/resources/zero_trust_dlp_entry.md +++ b/docs/resources/zero_trust_dlp_entry.md @@ -65,6 +65,7 @@ Optional: Read-Only: +- `ai_context_available` (Boolean) - `available` (Boolean) Indicates whether this entry can be made more or less sensitive by setting a confidence threshold. Profiles that use an entry with `available` set to true can use confidence thresholds diff --git a/docs/resources/zero_trust_dlp_predefined_profile.md b/docs/resources/zero_trust_dlp_predefined_profile.md index 346942fb3c..71a5eb7e4f 100644 --- a/docs/resources/zero_trust_dlp_predefined_profile.md +++ b/docs/resources/zero_trust_dlp_predefined_profile.md @@ -19,6 +19,7 @@ resource "cloudflare_zero_trust_dlp_predefined_profile" "example_zero_trust_dlp_ id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e" enabled = true }] + ai_context_enabled = true allowed_match_count = 0 confidence_threshold = "confidence_threshold" context_awareness = { @@ -42,6 +43,7 @@ resource "cloudflare_zero_trust_dlp_predefined_profile" "example_zero_trust_dlp_ ### Optional +- `ai_context_enabled` (Boolean) - `allowed_match_count` (Number) - `confidence_threshold` (String) - `context_awareness` (Attributes) Scan the context of predefined entries to only return matches surrounded by keywords. (see [below for nested schema](#nestedatt--context_awareness)) diff --git a/docs/resources/zero_trust_gateway_logging.md b/docs/resources/zero_trust_gateway_logging.md new file mode 100644 index 0000000000..ddfd051e1d --- /dev/null +++ b/docs/resources/zero_trust_gateway_logging.md @@ -0,0 +1,53 @@ +--- +page_title: "cloudflare_zero_trust_gateway_logging Resource - Cloudflare" +subcategory: "" +description: |- + +--- + +# cloudflare_zero_trust_gateway_logging (Resource) + + + +## Example Usage + +```terraform +resource "cloudflare_zero_trust_gateway_logging" "example_zero_trust_gateway_logging" { + account_id = "699d98642c564d2e855e9661899b7252" + redact_pii = true + settings_by_rule_type = { + dns = { + + } + http = { + + } + l4 = { + + } + } +} +``` + + +## Schema + +### Required + +- `account_id` (String) + +### Optional + +- `redact_pii` (Boolean) Redact personally identifiable information from activity logging (PII fields are: source IP, user email, user ID, device ID, URL, referrer, user agent). +- `settings_by_rule_type` (Attributes) Logging settings by rule type. (see [below for nested schema](#nestedatt--settings_by_rule_type)) + + +### Nested Schema for `settings_by_rule_type` + +Optional: + +- `dns` (String) Logging settings for DNS firewall. +- `http` (String) Logging settings for HTTP/HTTPS firewall. +- `l4` (String) Logging settings for Network firewall. + + diff --git a/docs/resources/zone.md b/docs/resources/zone.md index 2294086190..b9f87805c3 100644 --- a/docs/resources/zone.md +++ b/docs/resources/zone.md @@ -57,6 +57,7 @@ domain. If development mode has never been enabled, this value is 0. true value means the zone will not receive security or performance benefits. - `status` (String) The zone status on Cloudflare. +- `verification_key` (String) Verification key for partial zone setup. ### Nested Schema for `account` diff --git a/docs/resources/zone_cache_reserve.md b/docs/resources/zone_cache_reserve.md index 33ef286e9e..9072589300 100644 --- a/docs/resources/zone_cache_reserve.md +++ b/docs/resources/zone_cache_reserve.md @@ -34,7 +34,6 @@ resource "cloudflare_zone_cache_reserve" "example_zone_cache_reserve" { - `editable` (Boolean) Whether the setting is editable - `id` (String) Identifier - `modified_on` (String) Last time this setting was modified. -- `zone_setting_id` (String) ID of the zone setting. ## Import diff --git a/examples/data-sources/cloudflare_api_token_permissions_groups/data-source.tf b/examples/data-sources/cloudflare_api_token_permissions_groups/data-source.tf new file mode 100644 index 0000000000..b1566883b0 --- /dev/null +++ b/examples/data-sources/cloudflare_api_token_permissions_groups/data-source.tf @@ -0,0 +1,3 @@ +data "cloudflare_api_token_permissions_groups" "example_api_token_permissions_groups" { + account_id = "eb78d65290b24279ba6f44721b3ea3c4" +} diff --git a/examples/data-sources/cloudflare_botnet_feed_config_asn/data-source.tf b/examples/data-sources/cloudflare_botnet_feed_config_asn/data-source.tf new file mode 100644 index 0000000000..c02e6ae896 --- /dev/null +++ b/examples/data-sources/cloudflare_botnet_feed_config_asn/data-source.tf @@ -0,0 +1,3 @@ +data "cloudflare_botnet_feed_config_asn" "example_botnet_feed_config_asn" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" +} diff --git a/examples/data-sources/cloudflare_dns_settings/data-source.tf b/examples/data-sources/cloudflare_dns_settings/data-source.tf new file mode 100644 index 0000000000..2970bdb37a --- /dev/null +++ b/examples/data-sources/cloudflare_dns_settings/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_dns_settings" "example_dns_settings" { + account_id = "account_id" + zone_id = "zone_id" +} diff --git a/examples/data-sources/cloudflare_dns_settings_internal_view/data-source.tf b/examples/data-sources/cloudflare_dns_settings_internal_view/data-source.tf new file mode 100644 index 0000000000..264b0feaec --- /dev/null +++ b/examples/data-sources/cloudflare_dns_settings_internal_view/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_dns_settings_internal_view" "example_dns_settings_internal_view" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + view_id = "023e105f4ecef8ad9ca31a8372d0c353" +} diff --git a/examples/data-sources/cloudflare_dns_settings_internal_views/data-source.tf b/examples/data-sources/cloudflare_dns_settings_internal_views/data-source.tf new file mode 100644 index 0000000000..848c1859cc --- /dev/null +++ b/examples/data-sources/cloudflare_dns_settings_internal_views/data-source.tf @@ -0,0 +1,12 @@ +data "cloudflare_dns_settings_internal_views" "example_dns_settings_internal_views" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + name = { + contains = "view" + endswith = "ew" + exact = "my view" + startswith = "my" + } + order = "name" + zone_id = "ae29bea30e2e427ba9cd8d78b628177b" + zone_name = "www.example.com" +} diff --git a/examples/data-sources/cloudflare_ip_ranges/data-source.tf b/examples/data-sources/cloudflare_ip_ranges/data-source.tf new file mode 100644 index 0000000000..8ccf406e1c --- /dev/null +++ b/examples/data-sources/cloudflare_ip_ranges/data-source.tf @@ -0,0 +1,3 @@ +data "cloudflare_ip_ranges" "example_ip_ranges" { + networks = "networks" +} diff --git a/examples/data-sources/cloudflare_magic_transit_sites/data-source.tf b/examples/data-sources/cloudflare_magic_transit_sites/data-source.tf index dade6daef9..3504928485 100644 --- a/examples/data-sources/cloudflare_magic_transit_sites/data-source.tf +++ b/examples/data-sources/cloudflare_magic_transit_sites/data-source.tf @@ -1,4 +1,4 @@ data "cloudflare_magic_transit_sites" "example_magic_transit_sites" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" - connector_identifier = "023e105f4ecef8ad9ca31a8372d0c353" + connectorid = "023e105f4ecef8ad9ca31a8372d0c353" } diff --git a/examples/data-sources/cloudflare_r2_bucket_cors/data-source.tf b/examples/data-sources/cloudflare_r2_bucket_cors/data-source.tf new file mode 100644 index 0000000000..cceb87b4a6 --- /dev/null +++ b/examples/data-sources/cloudflare_r2_bucket_cors/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_r2_bucket_cors" "example_r2_bucket_cors" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} diff --git a/examples/data-sources/cloudflare_r2_bucket_event_notification/data-source.tf b/examples/data-sources/cloudflare_r2_bucket_event_notification/data-source.tf new file mode 100644 index 0000000000..872eb590b8 --- /dev/null +++ b/examples/data-sources/cloudflare_r2_bucket_event_notification/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_r2_bucket_event_notification" "example_r2_bucket_event_notification" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} diff --git a/examples/data-sources/cloudflare_r2_bucket_lifecycle/data-source.tf b/examples/data-sources/cloudflare_r2_bucket_lifecycle/data-source.tf new file mode 100644 index 0000000000..22ef6a5590 --- /dev/null +++ b/examples/data-sources/cloudflare_r2_bucket_lifecycle/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_r2_bucket_lifecycle" "example_r2_bucket_lifecycle" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} diff --git a/examples/data-sources/cloudflare_r2_bucket_lock/data-source.tf b/examples/data-sources/cloudflare_r2_bucket_lock/data-source.tf new file mode 100644 index 0000000000..2ca348d832 --- /dev/null +++ b/examples/data-sources/cloudflare_r2_bucket_lock/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_r2_bucket_lock" "example_r2_bucket_lock" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} diff --git a/examples/data-sources/cloudflare_r2_bucket_sippy/data-source.tf b/examples/data-sources/cloudflare_r2_bucket_sippy/data-source.tf new file mode 100644 index 0000000000..c38de1974c --- /dev/null +++ b/examples/data-sources/cloudflare_r2_bucket_sippy/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_r2_bucket_sippy" "example_r2_bucket_sippy" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" +} diff --git a/examples/data-sources/cloudflare_workers_route/data-source.tf b/examples/data-sources/cloudflare_workers_route/data-source.tf new file mode 100644 index 0000000000..644d6acc42 --- /dev/null +++ b/examples/data-sources/cloudflare_workers_route/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_workers_route" "example_workers_route" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" + route_id = "023e105f4ecef8ad9ca31a8372d0c353" +} diff --git a/examples/data-sources/cloudflare_workers_routes/data-source.tf b/examples/data-sources/cloudflare_workers_routes/data-source.tf new file mode 100644 index 0000000000..26387578dc --- /dev/null +++ b/examples/data-sources/cloudflare_workers_routes/data-source.tf @@ -0,0 +1,3 @@ +data "cloudflare_workers_routes" "example_workers_routes" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" +} diff --git a/examples/data-sources/cloudflare_zero_trust_access_infrastructure_targets/data-source.tf b/examples/data-sources/cloudflare_zero_trust_access_infrastructure_targets/data-source.tf index 96a5f21053..33fb1af8a0 100644 --- a/examples/data-sources/cloudflare_zero_trust_access_infrastructure_targets/data-source.tf +++ b/examples/data-sources/cloudflare_zero_trust_access_infrastructure_targets/data-source.tf @@ -5,11 +5,17 @@ data "cloudflare_zero_trust_access_infrastructure_targets" "example_zero_trust_a direction = "asc" hostname = "hostname" hostname_contains = "hostname_contains" + ip_like = "ip_like" ip_v4 = "ip_v4" ip_v6 = "ip_v6" ips = ["string"] + ipv4_end = "ipv4_end" + ipv4_start = "ipv4_start" + ipv6_end = "ipv6_end" + ipv6_start = "ipv6_start" modified_after = "2019-12-27T18:11:19.117Z" modified_before = "2019-12-27T18:11:19.117Z" order = "hostname" + target_ids = ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"] virtual_network_id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e" } diff --git a/examples/data-sources/cloudflare_zero_trust_gateway_logging/data-source.tf b/examples/data-sources/cloudflare_zero_trust_gateway_logging/data-source.tf new file mode 100644 index 0000000000..fe933bb3ef --- /dev/null +++ b/examples/data-sources/cloudflare_zero_trust_gateway_logging/data-source.tf @@ -0,0 +1,3 @@ +data "cloudflare_zero_trust_gateway_logging" "example_zero_trust_gateway_logging" { + account_id = "699d98642c564d2e855e9661899b7252" +} diff --git a/examples/data-sources/cloudflare_zero_trust_tunnel_cloudflared_token/data-source.tf b/examples/data-sources/cloudflare_zero_trust_tunnel_cloudflared_token/data-source.tf new file mode 100644 index 0000000000..1a92d19b3e --- /dev/null +++ b/examples/data-sources/cloudflare_zero_trust_tunnel_cloudflared_token/data-source.tf @@ -0,0 +1,4 @@ +data "cloudflare_zero_trust_tunnel_cloudflared_token" "example_zero_trust_tunnel_cloudflared_token" { + account_id = "699d98642c564d2e855e9661899b7252" + tunnel_id = "f70ff985-a4ef-4643-bbbc-4a0ed4fc8415" +} diff --git a/examples/resources/cloudflare_account_token/resource.tf b/examples/resources/cloudflare_account_token/resource.tf index e21509ae46..7f3ad0cc20 100644 --- a/examples/resources/cloudflare_account_token/resource.tf +++ b/examples/resources/cloudflare_account_token/resource.tf @@ -4,11 +4,13 @@ resource "cloudflare_account_token" "example_account_token" { policies = [{ effect = "allow" permission_groups = [{ + id = "c8fed203ed3043cba015a93ad1616f1f" meta = { key = "key" value = "value" } }, { + id = "82e64a83756745bbbb1c9c2701bf816b" meta = { key = "key" value = "value" diff --git a/examples/resources/cloudflare_api_token/resource.tf b/examples/resources/cloudflare_api_token/resource.tf index aa8be49a32..60b090078e 100644 --- a/examples/resources/cloudflare_api_token/resource.tf +++ b/examples/resources/cloudflare_api_token/resource.tf @@ -3,11 +3,13 @@ resource "cloudflare_api_token" "example_api_token" { policies = [{ effect = "allow" permission_groups = [{ + id = "c8fed203ed3043cba015a93ad1616f1f" meta = { key = "key" value = "value" } }, { + id = "82e64a83756745bbbb1c9c2701bf816b" meta = { key = "key" value = "value" diff --git a/examples/resources/cloudflare_cloudforce_one_request_asset/import.sh b/examples/resources/cloudflare_cloudforce_one_request_asset/import.sh new file mode 100755 index 0000000000..9718c5b7b7 --- /dev/null +++ b/examples/resources/cloudflare_cloudforce_one_request_asset/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_cloudforce_one_request_asset.example '//' diff --git a/examples/resources/cloudflare_custom_hostname/resource.tf b/examples/resources/cloudflare_custom_hostname/resource.tf index 16971c2afc..81dc39c663 100644 --- a/examples/resources/cloudflare_custom_hostname/resource.tf +++ b/examples/resources/cloudflare_custom_hostname/resource.tf @@ -5,6 +5,20 @@ resource "cloudflare_custom_hostname" "example_custom_hostname" { bundle_method = "ubiquitous" certificate_authority = "digicert" cloudflare_branding = false + custom_cert_bundle = [{ + custom_certificate = </' diff --git a/examples/resources/cloudflare_dns_settings_internal_view/resource.tf b/examples/resources/cloudflare_dns_settings_internal_view/resource.tf new file mode 100644 index 0000000000..a21cea75a5 --- /dev/null +++ b/examples/resources/cloudflare_dns_settings_internal_view/resource.tf @@ -0,0 +1,5 @@ +resource "cloudflare_dns_settings_internal_view" "example_dns_settings_internal_view" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + name = "my view" + zones = ["372e67954025e0ba6aaa6d586b9e0b59"] +} diff --git a/examples/resources/cloudflare_email_security_block_sender/resource.tf b/examples/resources/cloudflare_email_security_block_sender/resource.tf index 178e31ca53..2de0ef8083 100644 --- a/examples/resources/cloudflare_email_security_block_sender/resource.tf +++ b/examples/resources/cloudflare_email_security_block_sender/resource.tf @@ -1,7 +1,7 @@ resource "cloudflare_email_security_block_sender" "example_email_security_block_sender" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" - is_regex = false - pattern = "test@example.com" + is_regex = true + pattern = "x" pattern_type = "EMAIL" - comments = "block sender with email test@example.com" + comments = "comments" } diff --git a/examples/resources/cloudflare_email_security_trusted_domains/resource.tf b/examples/resources/cloudflare_email_security_trusted_domains/resource.tf index af22e1fbe1..68f09342d0 100644 --- a/examples/resources/cloudflare_email_security_trusted_domains/resource.tf +++ b/examples/resources/cloudflare_email_security_trusted_domains/resource.tf @@ -1,8 +1,8 @@ resource "cloudflare_email_security_trusted_domains" "example_email_security_trusted_domains" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" is_recent = true - is_regex = false - is_similarity = false - pattern = "example.com" - comments = null + is_regex = true + is_similarity = true + pattern = "x" + comments = "comments" } diff --git a/examples/resources/cloudflare_filter/import.sh b/examples/resources/cloudflare_filter/import.sh new file mode 100755 index 0000000000..14c982027f --- /dev/null +++ b/examples/resources/cloudflare_filter/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_filter.example '/' diff --git a/examples/resources/cloudflare_firewall_rule/import.sh b/examples/resources/cloudflare_firewall_rule/import.sh new file mode 100755 index 0000000000..8d17302eb8 --- /dev/null +++ b/examples/resources/cloudflare_firewall_rule/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_firewall_rule.example '/' diff --git a/examples/resources/cloudflare_magic_transit_site_lan/import.sh b/examples/resources/cloudflare_magic_transit_site_lan/import.sh new file mode 100755 index 0000000000..1e6e9e3743 --- /dev/null +++ b/examples/resources/cloudflare_magic_transit_site_lan/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_magic_transit_site_lan.example '//' diff --git a/examples/resources/cloudflare_magic_transit_site_lan/resource.tf b/examples/resources/cloudflare_magic_transit_site_lan/resource.tf index f1c0e8ecdb..57f914422a 100644 --- a/examples/resources/cloudflare_magic_transit_site_lan/resource.tf +++ b/examples/resources/cloudflare_magic_transit_site_lan/resource.tf @@ -24,6 +24,7 @@ resource "cloudflare_magic_transit_site_lan" "example_magic_transit_site_lan" { dhcp_pool_end = "192.0.2.1" dhcp_pool_start = "192.0.2.1" dns_server = "192.0.2.1" + dns_servers = ["192.0.2.1"] reservations = { "00:11:22:33:44:55" = "192.0.2.100" "AA:BB:CC:DD:EE:FF" = "192.168.1.101" diff --git a/examples/resources/cloudflare_magic_transit_site_wan/import.sh b/examples/resources/cloudflare_magic_transit_site_wan/import.sh new file mode 100755 index 0000000000..827bc8f6f1 --- /dev/null +++ b/examples/resources/cloudflare_magic_transit_site_wan/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_magic_transit_site_wan.example '//' diff --git a/examples/resources/cloudflare_r2_bucket/import.sh b/examples/resources/cloudflare_r2_bucket/import.sh index 909d275aac..4e7d38c896 100755 --- a/examples/resources/cloudflare_r2_bucket/import.sh +++ b/examples/resources/cloudflare_r2_bucket/import.sh @@ -1 +1 @@ -$ terraform import cloudflare_r2_bucket.example '/' +$ terraform import cloudflare_r2_bucket.example '//' diff --git a/examples/resources/cloudflare_r2_bucket_cors/resource.tf b/examples/resources/cloudflare_r2_bucket_cors/resource.tf new file mode 100644 index 0000000000..842cfecf98 --- /dev/null +++ b/examples/resources/cloudflare_r2_bucket_cors/resource.tf @@ -0,0 +1,14 @@ +resource "cloudflare_r2_bucket_cors" "example_r2_bucket_cors" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + allowed = { + methods = ["GET"] + origins = ["http://localhost:3000"] + headers = ["x-requested-by"] + } + id = "Allow Local Development" + expose_headers = ["Content-Encoding"] + max_age_seconds = 3600 + }] +} diff --git a/examples/resources/cloudflare_r2_bucket_event_notification/resource.tf b/examples/resources/cloudflare_r2_bucket_event_notification/resource.tf new file mode 100644 index 0000000000..55bd055362 --- /dev/null +++ b/examples/resources/cloudflare_r2_bucket_event_notification/resource.tf @@ -0,0 +1,11 @@ +resource "cloudflare_r2_bucket_event_notification" "example_r2_bucket_event_notification" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + queue_id = "queue_id" + rules = [{ + actions = ["PutObject", "CopyObject"] + description = "Notifications from source bucket to queue" + prefix = "img/" + suffix = ".jpeg" + }] +} diff --git a/examples/resources/cloudflare_r2_bucket_lifecycle/resource.tf b/examples/resources/cloudflare_r2_bucket_lifecycle/resource.tf new file mode 100644 index 0000000000..c85aee184a --- /dev/null +++ b/examples/resources/cloudflare_r2_bucket_lifecycle/resource.tf @@ -0,0 +1,30 @@ +resource "cloudflare_r2_bucket_lifecycle" "example_r2_bucket_lifecycle" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + id = "Expire all objects older than 24 hours" + conditions = { + prefix = "prefix" + } + enabled = true + abort_multipart_uploads_transition = { + condition = { + max_age = 0 + type = "Age" + } + } + delete_objects_transition = { + condition = { + max_age = 0 + type = "Age" + } + } + storage_class_transitions = [{ + condition = { + max_age = 0 + type = "Age" + } + storage_class = "InfrequentAccess" + }] + }] +} diff --git a/examples/resources/cloudflare_r2_bucket_lock/resource.tf b/examples/resources/cloudflare_r2_bucket_lock/resource.tf new file mode 100644 index 0000000000..37af91d8f4 --- /dev/null +++ b/examples/resources/cloudflare_r2_bucket_lock/resource.tf @@ -0,0 +1,13 @@ +resource "cloudflare_r2_bucket_lock" "example_r2_bucket_lock" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + rules = [{ + id = "Lock all objects for 24 hours" + condition = { + max_age_seconds = 100 + type = "Age" + } + enabled = true + prefix = "prefix" + }] +} diff --git a/examples/resources/cloudflare_r2_bucket_sippy/resource.tf b/examples/resources/cloudflare_r2_bucket_sippy/resource.tf new file mode 100644 index 0000000000..a48e2e9773 --- /dev/null +++ b/examples/resources/cloudflare_r2_bucket_sippy/resource.tf @@ -0,0 +1,16 @@ +resource "cloudflare_r2_bucket_sippy" "example_r2_bucket_sippy" { + account_id = "023e105f4ecef8ad9ca31a8372d0c353" + bucket_name = "example-bucket" + destination = { + access_key_id = "accessKeyId" + provider = "r2" + secret_access_key = "secretAccessKey" + } + source = { + access_key_id = "accessKeyId" + bucket = "bucket" + provider = "aws" + region = "region" + secret_access_key = "secretAccessKey" + } +} diff --git a/examples/resources/cloudflare_r2_custom_domain/resource.tf b/examples/resources/cloudflare_r2_custom_domain/resource.tf index 7db350cdd4..a44cf77d00 100644 --- a/examples/resources/cloudflare_r2_custom_domain/resource.tf +++ b/examples/resources/cloudflare_r2_custom_domain/resource.tf @@ -1,8 +1,8 @@ resource "cloudflare_r2_custom_domain" "example_r2_custom_domain" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" bucket_name = "example-bucket" - domain = "prefix.example-domain.com" + domain = "domain" enabled = true - zone_id = "36ca64a6d92827b8a6b90be344bb1bfd" + zone_id = "zoneId" min_tls = "1.0" } diff --git a/examples/resources/cloudflare_waiting_room_rules/import.sh b/examples/resources/cloudflare_waiting_room_rules/import.sh new file mode 100755 index 0000000000..ed25216747 --- /dev/null +++ b/examples/resources/cloudflare_waiting_room_rules/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_waiting_room_rules.example '/' diff --git a/examples/resources/cloudflare_workers_route/resource.tf b/examples/resources/cloudflare_workers_route/resource.tf new file mode 100644 index 0000000000..8987a916f7 --- /dev/null +++ b/examples/resources/cloudflare_workers_route/resource.tf @@ -0,0 +1,5 @@ +resource "cloudflare_workers_route" "example_workers_route" { + zone_id = "023e105f4ecef8ad9ca31a8372d0c353" + pattern = "example.net/*" + script = "this-is_my_script-01" +} diff --git a/examples/resources/cloudflare_workers_script/resource.tf b/examples/resources/cloudflare_workers_script/resource.tf index e8415327e3..83e65c27c1 100644 --- a/examples/resources/cloudflare_workers_script/resource.tf +++ b/examples/resources/cloudflare_workers_script/resource.tf @@ -1,56 +1,55 @@ resource "cloudflare_workers_script" "example_workers_script" { account_id = "023e105f4ecef8ad9ca31a8372d0c353" script_name = "this-is_my_script-01" - metadata = { - assets = { - config = { - html_handling = "auto-trailing-slash" - not_found_handling = "none" - run_worker_first = false - serve_directly = true - } - jwt = "jwt" + assets = { + config = { + html_handling = "auto-trailing-slash" + not_found_handling = "none" + run_worker_first = false + serve_directly = true } - bindings = [{ - name = "MY_ENV_VAR" - type = "plain_text" + jwt = "jwt" + } + bindings = [{ + name = "MY_ENV_VAR" + text = "my_data" + type = "plain_text" + }] + body_part = "worker.js" + compatibility_date = "2021-01-01" + compatibility_flags = ["nodejs_compat"] + keep_assets = false + keep_bindings = ["string"] + logpush = false + main_module = "worker.js" + migrations = { + deleted_classes = ["string"] + new_classes = ["string"] + new_sqlite_classes = ["string"] + new_tag = "v2" + old_tag = "v1" + renamed_classes = [{ + from = "from" + to = "to" }] - body_part = "worker.js" - compatibility_date = "2021-01-01" - compatibility_flags = ["nodejs_compat"] - keep_assets = false - keep_bindings = ["string"] - logpush = false - main_module = "worker.js" - migrations = { - deleted_classes = ["string"] - new_classes = ["string"] - new_sqlite_classes = ["string"] - new_tag = "v2" - old_tag = "v1" - renamed_classes = [{ - from = "from" - to = "to" - }] - transferred_classes = [{ - from = "from" - from_script = "from_script" - to = "to" - }] - } - observability = { - enabled = true - head_sampling_rate = 0.1 - } - placement = { - mode = "smart" - } - tags = ["string"] - tail_consumers = [{ - service = "my-log-consumer" - environment = "production" - namespace = "my-namespace" + transferred_classes = [{ + from = "from" + from_script = "from_script" + to = "to" }] - usage_model = "standard" } + observability = { + enabled = true + head_sampling_rate = 0.1 + } + placement = { + mode = "smart" + } + tags = ["string"] + tail_consumers = [{ + service = "my-log-consumer" + environment = "production" + namespace = "my-namespace" + }] + usage_model = "standard" } diff --git a/examples/resources/cloudflare_zero_trust_device_default_profile/import.sh b/examples/resources/cloudflare_zero_trust_device_default_profile/import.sh new file mode 100755 index 0000000000..d57081ad8a --- /dev/null +++ b/examples/resources/cloudflare_zero_trust_device_default_profile/import.sh @@ -0,0 +1 @@ +$ terraform import cloudflare_zero_trust_device_default_profile.example '' diff --git a/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf b/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf index d912b202fc..adbd92ec54 100644 --- a/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf +++ b/examples/resources/cloudflare_zero_trust_device_managed_networks/resource.tf @@ -1,7 +1,7 @@ resource "cloudflare_zero_trust_device_managed_networks" "example_zero_trust_device_managed_networks" { account_id = "699d98642c564d2e855e9661899b7252" config = { - tls_sockaddr = "foobar:1234" + tls_sockaddr = "foo.bar:1234" sha256 = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c" } name = "managed-network-1" diff --git a/examples/resources/cloudflare_zero_trust_dlp_custom_profile/resource.tf b/examples/resources/cloudflare_zero_trust_dlp_custom_profile/resource.tf index a3a06e2935..823c9db146 100644 --- a/examples/resources/cloudflare_zero_trust_dlp_custom_profile/resource.tf +++ b/examples/resources/cloudflare_zero_trust_dlp_custom_profile/resource.tf @@ -10,6 +10,7 @@ resource "cloudflare_zero_trust_dlp_custom_profile" "example_zero_trust_dlp_cust } }] name = "name" + ai_context_enabled = true allowed_match_count = 5 confidence_threshold = "confidence_threshold" context_awareness = { diff --git a/examples/resources/cloudflare_zero_trust_dlp_predefined_profile/resource.tf b/examples/resources/cloudflare_zero_trust_dlp_predefined_profile/resource.tf index e72186162c..f7b5af8ae3 100644 --- a/examples/resources/cloudflare_zero_trust_dlp_predefined_profile/resource.tf +++ b/examples/resources/cloudflare_zero_trust_dlp_predefined_profile/resource.tf @@ -5,6 +5,7 @@ resource "cloudflare_zero_trust_dlp_predefined_profile" "example_zero_trust_dlp_ id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e" enabled = true }] + ai_context_enabled = true allowed_match_count = 0 confidence_threshold = "confidence_threshold" context_awareness = { diff --git a/examples/resources/cloudflare_zero_trust_gateway_logging/resource.tf b/examples/resources/cloudflare_zero_trust_gateway_logging/resource.tf new file mode 100644 index 0000000000..f754cf35fe --- /dev/null +++ b/examples/resources/cloudflare_zero_trust_gateway_logging/resource.tf @@ -0,0 +1,15 @@ +resource "cloudflare_zero_trust_gateway_logging" "example_zero_trust_gateway_logging" { + account_id = "699d98642c564d2e855e9661899b7252" + redact_pii = true + settings_by_rule_type = { + dns = { + + } + http = { + + } + l4 = { + + } + } +} diff --git a/go.mod b/go.mod index 78effa7551..cd93cba11b 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/cloudflare/terraform-provider-cloudflare go 1.22.7 require ( + github.com/cloudflare/cloudflare-go/v4 v4.1.0 github.com/aws/aws-sdk-go-v2 v1.31.0 github.com/aws/aws-sdk-go-v2/config v1.27.36 github.com/aws/aws-sdk-go-v2/credentials v1.17.34 github.com/aws/aws-sdk-go-v2/service/s3 v1.63.0 github.com/cloudflare/cloudflare-go v0.104.0 - github.com/cloudflare/cloudflare-go/v4 v4.0.0 github.com/davecgh/go-spew v1.1.1 github.com/hashicorp/terraform-plugin-docs v0.20.1 github.com/hashicorp/terraform-plugin-framework v1.13.0 diff --git a/go.sum b/go.sum index cc846abc23..e3e781f3e6 100644 --- a/go.sum +++ b/go.sum @@ -65,10 +65,10 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/cloudflare-go/v4 v4.1.0 h1:1SjQZaPbUe23fSoCuMuN7EblVo+RIldNGd4pfkPCpW4= +github.com/cloudflare/cloudflare-go/v4 v4.1.0/go.mod h1:XcYpLe7Mf6FN87kXzEWVnJ6z+vskW/k6eUqgqfhFE9k= github.com/cloudflare/cloudflare-go v0.104.0 h1:R/lB0dZupaZbOgibAH/BRrkFbZ6Acn/WsKg2iX2xXuY= github.com/cloudflare/cloudflare-go v0.104.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM= -github.com/cloudflare/cloudflare-go/v4 v4.0.0 h1:qVtUvfsnH2n7aCZOIapbiE3w/FPNrHp7s578OLIdbo8= -github.com/cloudflare/cloudflare-go/v4 v4.0.0/go.mod h1:XcYpLe7Mf6FN87kXzEWVnJ6z+vskW/k6eUqgqfhFE9k= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 8879740785..e3bd8dfc65 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -188,6 +188,13 @@ func TestAccPreCheck_HyperdriveWithAccess(t *testing.T) { } } +// Test helper method checking `CLOUDFLARE_INTERNAL_ZONE_ID` is present. +func TestAccPreCheck_InternalZoneID(t *testing.T) { + if v := os.Getenv("CLOUDFLARE_INTERNAL_ZONE_ID"); v == "" { + t.Skip("Skipping acceptance test as CLOUDFLARE_INTERNAL_ZONE_ID is not set") + } +} + // TestAccSkipForDefaultZone is used for skipping over tests that are not run by // default on usual acceptance test suite account. func TestAccSkipForDefaultZone(t *testing.T, reason string) { diff --git a/internal/apiform/encoder.go b/internal/apiform/encoder.go index 57f120ef48..7bb3f3fdb6 100644 --- a/internal/apiform/encoder.go +++ b/internal/apiform/encoder.go @@ -402,7 +402,7 @@ func (e *encoder) newReaderTypeEncoder() encoderFunc { filename = path.Base(named.Name()) } if typed, ok := reader.(interface{ ContentType() string }); ok { - contentType = path.Base(typed.ContentType()) + contentType = typed.ContentType() } // Below is taken almost 1-for-1 from [multipart.CreateFormFile] diff --git a/internal/provider.go b/internal/provider.go index 59f4e8a1f4..fcb222c1af 100644 --- a/internal/provider.go +++ b/internal/provider.go @@ -31,6 +31,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/authenticated_origin_pulls" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/authenticated_origin_pulls_certificate" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/bot_management" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/botnet_feed_config_asn" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/byo_ip_prefix" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/calls_sfu_app" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/calls_turn_app" @@ -48,6 +49,8 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dcv_delegation" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_firewall" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_record" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings_internal_view" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_zone_transfers_acl" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_zone_transfers_incoming" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_zone_transfers_outgoing" @@ -68,6 +71,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/hyperdrive_config" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/image" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/image_variant" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/ip_ranges" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/keyless_certificate" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/leaked_credential_check" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/leaked_credential_check_rule" @@ -108,6 +112,13 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/queue" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/queue_consumer" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_cors" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_event_notification" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lifecycle" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lock" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_sippy" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_custom_domain" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_managed_domain" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/rate_limit" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/regional_hostname" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/regional_tiered_cache" @@ -144,6 +155,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_for_platforms_dispatch_namespace" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_kv" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_kv_namespace" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_route" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_script" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_script_subdomain" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_secret" @@ -176,6 +188,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_app_types" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_categories" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_certificate" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_logging" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_policy" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_proxy_endpoint" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_settings" @@ -186,6 +199,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_config" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_route" + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_token" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_virtual_network" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zone" "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zone_cache_reserve" @@ -388,6 +402,8 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re dns_firewall.NewResource, zone_dnssec.NewResource, dns_record.NewResource, + dns_settings.NewResource, + dns_settings_internal_view.NewResource, dns_zone_transfers_incoming.NewResource, dns_zone_transfers_outgoing.NewResource, dns_zone_transfers_acl.NewResource, @@ -420,6 +436,7 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re waiting_room_rules.NewResource, waiting_room_settings.NewResource, web3_hostname.NewResource, + workers_route.NewResource, workers_script.NewResource, workers_script_subdomain.NewResource, workers_cron_trigger.NewResource, @@ -473,6 +490,13 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re notification_policy.NewResource, d1_database.NewResource, r2_bucket.NewResource, + r2_bucket_lifecycle.NewResource, + r2_bucket_cors.NewResource, + r2_custom_domain.NewResource, + r2_managed_domain.NewResource, + r2_bucket_event_notification.NewResource, + r2_bucket_lock.NewResource, + r2_bucket_sippy.NewResource, workers_for_platforms_dispatch_namespace.NewResource, workers_secret.NewResource, zero_trust_dex_test.NewResource, @@ -506,6 +530,7 @@ func (p *CloudflareProvider) Resources(ctx context.Context) []func() resource.Re zero_trust_gateway_settings.NewResource, zero_trust_list.NewResource, zero_trust_dns_location.NewResource, + zero_trust_gateway_logging.NewResource, zero_trust_gateway_proxy_endpoint.NewResource, zero_trust_gateway_policy.NewResource, zero_trust_gateway_certificate.NewResource, @@ -546,9 +571,11 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc account_subscription.NewAccountSubscriptionDataSource, account_token.NewAccountTokenDataSource, account_token.NewAccountTokensDataSource, + api_token_permissions_groups.NewAPITokenPermissionsGroupsDataSource, api_token_permissions_groups.NewAPITokenPermissionsGroupsListDataSource, origin_ca_certificate.NewOriginCACertificateDataSource, origin_ca_certificate.NewOriginCACertificatesDataSource, + ip_ranges.NewIPRangesDataSource, user.NewUserDataSource, api_token.NewAPITokenDataSource, api_token.NewAPITokensDataSource, @@ -582,6 +609,9 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc zone_dnssec.NewZoneDNSSECDataSource, dns_record.NewDNSRecordDataSource, dns_record.NewDNSRecordsDataSource, + dns_settings.NewDNSSettingsDataSource, + dns_settings_internal_view.NewDNSSettingsInternalViewDataSource, + dns_settings_internal_view.NewDNSSettingsInternalViewsDataSource, dns_zone_transfers_incoming.NewDNSZoneTransfersIncomingDataSource, dns_zone_transfers_outgoing.NewDNSZoneTransfersOutgoingDataSource, dns_zone_transfers_acl.NewDNSZoneTransfersACLDataSource, @@ -636,6 +666,8 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc waiting_room_settings.NewWaitingRoomSettingsDataSource, web3_hostname.NewWeb3HostnameDataSource, web3_hostname.NewWeb3HostnamesDataSource, + workers_route.NewWorkersRouteDataSource, + workers_route.NewWorkersRoutesDataSource, workers_script.NewWorkersScriptDataSource, workers_script.NewWorkersScriptsDataSource, workers_script_subdomain.NewWorkersScriptSubdomainDataSource, @@ -725,6 +757,12 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc d1_database.NewD1DatabaseDataSource, d1_database.NewD1DatabasesDataSource, r2_bucket.NewR2BucketDataSource, + r2_bucket_lifecycle.NewR2BucketLifecycleDataSource, + r2_bucket_cors.NewR2BucketCORSDataSource, + r2_custom_domain.NewR2CustomDomainDataSource, + r2_bucket_event_notification.NewR2BucketEventNotificationDataSource, + r2_bucket_lock.NewR2BucketLockDataSource, + r2_bucket_sippy.NewR2BucketSippyDataSource, workers_for_platforms_dispatch_namespace.NewWorkersForPlatformsDispatchNamespaceDataSource, workers_for_platforms_dispatch_namespace.NewWorkersForPlatformsDispatchNamespacesDataSource, workers_secret.NewWorkersSecretDataSource, @@ -769,6 +807,7 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc zero_trust_tunnel_cloudflared.NewZeroTrustTunnelCloudflaredDataSource, zero_trust_tunnel_cloudflared.NewZeroTrustTunnelCloudflaredsDataSource, zero_trust_tunnel_cloudflared_config.NewZeroTrustTunnelCloudflaredConfigDataSource, + zero_trust_tunnel_cloudflared_token.NewZeroTrustTunnelCloudflaredTokenDataSource, zero_trust_dlp_dataset.NewZeroTrustDLPDatasetDataSource, zero_trust_dlp_dataset.NewZeroTrustDLPDatasetsDataSource, zero_trust_dlp_custom_profile.NewZeroTrustDLPCustomProfileDataSource, @@ -782,6 +821,7 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc zero_trust_list.NewZeroTrustListsDataSource, zero_trust_dns_location.NewZeroTrustDNSLocationDataSource, zero_trust_dns_location.NewZeroTrustDNSLocationsDataSource, + zero_trust_gateway_logging.NewZeroTrustGatewayLoggingDataSource, zero_trust_gateway_proxy_endpoint.NewZeroTrustGatewayProxyEndpointDataSource, zero_trust_gateway_policy.NewZeroTrustGatewayPolicyDataSource, zero_trust_gateway_policy.NewZeroTrustGatewayPoliciesDataSource, @@ -821,6 +861,7 @@ func (p *CloudflareProvider) DataSources(ctx context.Context) []func() datasourc resource_group.NewResourceGroupDataSource, resource_group.NewResourceGroupsDataSource, cloud_connector_rules.NewCloudConnectorRulesListDataSource, + botnet_feed_config_asn.NewBotnetFeedConfigASNDataSource, leaked_credential_check.NewLeakedCredentialCheckDataSource, leaked_credential_check_rule.NewLeakedCredentialCheckRulesDataSource, content_scanning_expression.NewContentScanningExpressionsDataSource, diff --git a/internal/services/access_rule/data_source.go b/internal/services/access_rule/data_source.go index 48f2418cbf..7c7b2e6932 100644 --- a/internal/services/access_rule/data_source.go +++ b/internal/services/access_rule/data_source.go @@ -64,7 +64,7 @@ func (d *AccessRuleDataSource) Read(ctx context.Context, req datasource.ReadRequ return } - env := AccessRuleResultListDataSourceEnvelope{} + env := AccessRulesResultListDataSourceEnvelope{} page, err := d.client.Firewall.AccessRules.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *AccessRuleDataSource) Read(ctx context.Context, req datasource.ReadRequ } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.RuleID = ts[0].RuleID + data.RuleID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/access_rule/data_source_model.go b/internal/services/access_rule/data_source_model.go index e80e5bbf98..cf315ffc32 100644 --- a/internal/services/access_rule/data_source_model.go +++ b/internal/services/access_rule/data_source_model.go @@ -17,10 +17,6 @@ type AccessRuleResultDataSourceEnvelope struct { Result AccessRuleDataSourceModel `json:"result,computed"` } -type AccessRuleResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[AccessRuleDataSourceModel] `json:"result,computed"` -} - type AccessRuleDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` diff --git a/internal/services/account/data_source.go b/internal/services/account/data_source.go index 26d717c465..94ef80fd59 100644 --- a/internal/services/account/data_source.go +++ b/internal/services/account/data_source.go @@ -64,7 +64,7 @@ func (d *AccountDataSource) Read(ctx context.Context, req datasource.ReadRequest return } - env := AccountResultListDataSourceEnvelope{} + env := AccountsResultListDataSourceEnvelope{} page, err := d.client.Accounts.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *AccountDataSource) Read(ctx context.Context, req datasource.ReadRequest } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.AccountID = ts[0].AccountID + data.AccountID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/account/data_source_model.go b/internal/services/account/data_source_model.go index 507440b660..491d6a6d49 100644 --- a/internal/services/account/data_source_model.go +++ b/internal/services/account/data_source_model.go @@ -17,10 +17,6 @@ type AccountResultDataSourceEnvelope struct { Result AccountDataSourceModel `json:"result,computed"` } -type AccountResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[AccountDataSourceModel] `json:"result,computed"` -} - type AccountDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` diff --git a/internal/services/account_member/data_source.go b/internal/services/account_member/data_source.go index 14f8a2b122..171478ed26 100644 --- a/internal/services/account_member/data_source.go +++ b/internal/services/account_member/data_source.go @@ -64,7 +64,7 @@ func (d *AccountMemberDataSource) Read(ctx context.Context, req datasource.ReadR return } - env := AccountMemberResultListDataSourceEnvelope{} + env := AccountMembersResultListDataSourceEnvelope{} page, err := d.client.Accounts.Members.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *AccountMemberDataSource) Read(ctx context.Context, req datasource.ReadR } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.MemberID = ts[0].MemberID + data.MemberID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/account_member/data_source_model.go b/internal/services/account_member/data_source_model.go index 30582476ce..966a2fd068 100644 --- a/internal/services/account_member/data_source_model.go +++ b/internal/services/account_member/data_source_model.go @@ -16,10 +16,6 @@ type AccountMemberResultDataSourceEnvelope struct { Result AccountMemberDataSourceModel `json:"result,computed"` } -type AccountMemberResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[AccountMemberDataSourceModel] `json:"result,computed"` -} - type AccountMemberDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` MemberID types.String `tfsdk:"member_id" path:"member_id,optional"` diff --git a/internal/services/account_role/data_source_test.go b/internal/services/account_role/data_source_test.go new file mode 100644 index 0000000000..861a9490eb --- /dev/null +++ b/internal/services/account_role/data_source_test.go @@ -0,0 +1,61 @@ +package account_role_test + +import ( + "fmt" + "os" + "strconv" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/consts" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccCloudflareAccountRoles_Datasource(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := fmt.Sprintf("data.cloudflare_account_roles.%s", rnd) + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck_AccountID(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCloudflareAccountRoles_Config(rnd, accountID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, consts.AccountIDSchemaKey, accountID), + testAccCheckExampleWidgetExists(name), + ), + }, + }, + }) +} + +func testAccCheckExampleWidgetExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // retrieve the resource by name from state + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("ID is not set") + } + + i, _ := strconv.Atoi(rs.Primary.Attributes["result.#"]) + if i < 30 { + return fmt.Errorf("role size is suspiciously low. should be > 30, got: %d", i) + } + + return nil + } +} + +func testAccCloudflareAccountRoles_Config(rnd, accountID string) string { + return acctest.LoadTestCase("datasource.tf", rnd, accountID) +} diff --git a/internal/services/account_role/testdata/datasource.tf b/internal/services/account_role/testdata/datasource.tf new file mode 100644 index 0000000000..e4b5694a67 --- /dev/null +++ b/internal/services/account_role/testdata/datasource.tf @@ -0,0 +1,3 @@ +data "cloudflare_account_roles" "%[1]s" { + account_id = "%[2]s" +} diff --git a/internal/services/account_subscription/data_source_model.go b/internal/services/account_subscription/data_source_model.go index ac92dce8bc..54543bc714 100644 --- a/internal/services/account_subscription/data_source_model.go +++ b/internal/services/account_subscription/data_source_model.go @@ -7,6 +7,8 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/accounts" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,7 +18,15 @@ type AccountSubscriptionResultDataSourceEnvelope struct { } type AccountSubscriptionDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Currency types.String `tfsdk:"currency" json:"currency,computed"` + CurrentPeriodEnd timetypes.RFC3339 `tfsdk:"current_period_end" json:"current_period_end,computed" format:"date-time"` + CurrentPeriodStart timetypes.RFC3339 `tfsdk:"current_period_start" json:"current_period_start,computed" format:"date-time"` + Frequency types.String `tfsdk:"frequency" json:"frequency,computed"` + ID types.String `tfsdk:"id" json:"id,computed"` + Price types.Float64 `tfsdk:"price" json:"price,computed"` + State types.String `tfsdk:"state" json:"state,computed"` + RatePlan customfield.NestedObject[AccountSubscriptionRatePlanDataSourceModel] `tfsdk:"rate_plan" json:"rate_plan,computed"` } func (m *AccountSubscriptionDataSourceModel) toReadParams(_ context.Context) (params accounts.SubscriptionGetParams, diags diag.Diagnostics) { @@ -26,3 +36,13 @@ func (m *AccountSubscriptionDataSourceModel) toReadParams(_ context.Context) (pa return } + +type AccountSubscriptionRatePlanDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Currency types.String `tfsdk:"currency" json:"currency,computed"` + ExternallyManaged types.Bool `tfsdk:"externally_managed" json:"externally_managed,computed"` + IsContract types.Bool `tfsdk:"is_contract" json:"is_contract,computed"` + PublicName types.String `tfsdk:"public_name" json:"public_name,computed"` + Scope types.String `tfsdk:"scope" json:"scope,computed"` + Sets customfield.List[types.String] `tfsdk:"sets" json:"sets,computed"` +} diff --git a/internal/services/account_subscription/data_source_schema.go b/internal/services/account_subscription/data_source_schema.go index 081c7633aa..6092039773 100644 --- a/internal/services/account_subscription/data_source_schema.go +++ b/internal/services/account_subscription/data_source_schema.go @@ -5,8 +5,13 @@ package account_subscription import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*AccountSubscriptionDataSource)(nil) @@ -18,6 +23,106 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Identifier", Required: true, }, + "currency": schema.StringAttribute{ + Description: "The monetary unit in which pricing information is displayed.", + Computed: true, + }, + "current_period_end": schema.StringAttribute{ + Description: "The end of the current period and also when the next billing is due.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "current_period_start": schema.StringAttribute{ + Description: "When the current billing period started. May match initial_period_start if this is the first period.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "frequency": schema.StringAttribute{ + Description: "How often the subscription is renewed automatically.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "weekly", + "monthly", + "quarterly", + "yearly", + ), + }, + }, + "id": schema.StringAttribute{ + Description: "Subscription identifier tag.", + Computed: true, + }, + "price": schema.Float64Attribute{ + Description: "The price of the subscription that will be billed, in US dollars.", + Computed: true, + }, + "state": schema.StringAttribute{ + Description: "The state that the subscription is in.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "Trial", + "Provisioned", + "Paid", + "AwaitingPayment", + "Cancelled", + "Failed", + "Expired", + ), + }, + }, + "rate_plan": schema.SingleNestedAttribute{ + Description: "The rate plan applied to the subscription.", + Computed: true, + CustomType: customfield.NewNestedObjectType[AccountSubscriptionRatePlanDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of the rate plan.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "free", + "lite", + "pro", + "pro_plus", + "business", + "enterprise", + "partners_free", + "partners_pro", + "partners_business", + "partners_enterprise", + ), + }, + }, + "currency": schema.StringAttribute{ + Description: "The currency applied to the rate plan subscription.", + Computed: true, + }, + "externally_managed": schema.BoolAttribute{ + Description: "Whether this rate plan is managed externally from Cloudflare.", + Computed: true, + }, + "is_contract": schema.BoolAttribute{ + Description: "Whether a rate plan is enterprise-based (or newly adopted term contract).", + Computed: true, + }, + "public_name": schema.StringAttribute{ + Description: "The full name of the rate plan.", + Computed: true, + }, + "scope": schema.StringAttribute{ + Description: "The scope that this rate plan applies to.", + Computed: true, + }, + "sets": schema.ListAttribute{ + Description: "The list of sets this rate plan applies to.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, + }, }, } } diff --git a/internal/services/account_subscription/model.go b/internal/services/account_subscription/model.go index 2ba62beb95..bcc42e526f 100644 --- a/internal/services/account_subscription/model.go +++ b/internal/services/account_subscription/model.go @@ -5,6 +5,7 @@ package account_subscription import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -17,6 +18,12 @@ type AccountSubscriptionModel struct { SubscriptionIdentifier types.String `tfsdk:"subscription_identifier" path:"subscription_identifier,optional"` Frequency types.String `tfsdk:"frequency" json:"frequency,optional"` RatePlan customfield.NestedObject[AccountSubscriptionRatePlanModel] `tfsdk:"rate_plan" json:"rate_plan,computed_optional"` + Currency types.String `tfsdk:"currency" json:"currency,computed"` + CurrentPeriodEnd timetypes.RFC3339 `tfsdk:"current_period_end" json:"current_period_end,computed" format:"date-time"` + CurrentPeriodStart timetypes.RFC3339 `tfsdk:"current_period_start" json:"current_period_start,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` + Price types.Float64 `tfsdk:"price" json:"price,computed"` + State types.String `tfsdk:"state" json:"state,computed"` } func (m AccountSubscriptionModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/account_subscription/schema.go b/internal/services/account_subscription/schema.go index 518cf2aa47..6df34539f9 100644 --- a/internal/services/account_subscription/schema.go +++ b/internal/services/account_subscription/schema.go @@ -6,6 +6,7 @@ import ( "context" "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -51,6 +52,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { "id": schema.StringAttribute{ Description: "The ID of the rate plan.", Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "free", + "lite", + "pro", + "pro_plus", + "business", + "enterprise", + "partners_free", + "partners_pro", + "partners_business", + "partners_enterprise", + ), + }, }, "currency": schema.StringAttribute{ Description: "The currency applied to the rate plan subscription.", @@ -79,6 +94,43 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "currency": schema.StringAttribute{ + Description: "The monetary unit in which pricing information is displayed.", + Computed: true, + }, + "current_period_end": schema.StringAttribute{ + Description: "The end of the current period and also when the next billing is due.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "current_period_start": schema.StringAttribute{ + Description: "When the current billing period started. May match initial_period_start if this is the first period.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "id": schema.StringAttribute{ + Description: "Subscription identifier tag.", + Computed: true, + }, + "price": schema.Float64Attribute{ + Description: "The price of the subscription that will be billed, in US dollars.", + Computed: true, + }, + "state": schema.StringAttribute{ + Description: "The state that the subscription is in.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "Trial", + "Provisioned", + "Paid", + "AwaitingPayment", + "Cancelled", + "Failed", + "Expired", + ), + }, + }, }, } } diff --git a/internal/services/account_token/data_source.go b/internal/services/account_token/data_source.go index 8805e8a446..bcb158ed45 100644 --- a/internal/services/account_token/data_source.go +++ b/internal/services/account_token/data_source.go @@ -64,7 +64,7 @@ func (d *AccountTokenDataSource) Read(ctx context.Context, req datasource.ReadRe return } - env := AccountTokenResultListDataSourceEnvelope{} + env := AccountTokensResultListDataSourceEnvelope{} page, err := d.client.Accounts.Tokens.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *AccountTokenDataSource) Read(ctx context.Context, req datasource.ReadRe } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.TokenID = ts[0].TokenID + data.TokenID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/account_token/data_source_model.go b/internal/services/account_token/data_source_model.go index e5cb71f274..c5a13f601b 100644 --- a/internal/services/account_token/data_source_model.go +++ b/internal/services/account_token/data_source_model.go @@ -17,10 +17,6 @@ type AccountTokenResultDataSourceEnvelope struct { Result AccountTokenDataSourceModel `json:"result,computed"` } -type AccountTokenResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[AccountTokenDataSourceModel] `json:"result,computed"` -} - type AccountTokenDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TokenID types.String `tfsdk:"token_id" path:"token_id,optional"` diff --git a/internal/services/account_token/model.go b/internal/services/account_token/model.go index 574c8d897f..6aa8e5b480 100644 --- a/internal/services/account_token/model.go +++ b/internal/services/account_token/model.go @@ -44,7 +44,7 @@ type AccountTokenPoliciesModel struct { } type AccountTokenPoliciesPermissionGroupsModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` + ID types.String `tfsdk:"id" json:"id,required"` Meta *AccountTokenPoliciesPermissionGroupsMetaModel `tfsdk:"meta" json:"meta,optional"` Name types.String `tfsdk:"name" json:"name,computed"` } diff --git a/internal/services/account_token/schema.go b/internal/services/account_token/schema.go index 3c0f92cc2b..f3069622a3 100644 --- a/internal/services/account_token/schema.go +++ b/internal/services/account_token/schema.go @@ -58,7 +58,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Description: "Identifier of the group.", - Computed: true, + Required: true, }, "meta": schema.SingleNestedAttribute{ Description: "Attributes associated to the permission group.", diff --git a/internal/services/address_map/data_source_model.go b/internal/services/address_map/data_source_model.go index 1756d8eba5..962bbd244f 100644 --- a/internal/services/address_map/data_source_model.go +++ b/internal/services/address_map/data_source_model.go @@ -17,10 +17,6 @@ type AddressMapResultDataSourceEnvelope struct { Result AddressMapDataSourceModel `json:"result,computed"` } -type AddressMapResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[AddressMapDataSourceModel] `json:"result,computed"` -} - type AddressMapDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` AddressMapID types.String `tfsdk:"address_map_id" path:"address_map_id,optional"` diff --git a/internal/services/api_shield_operation/data_source.go b/internal/services/api_shield_operation/data_source.go index 040b7282c0..6274d71390 100644 --- a/internal/services/api_shield_operation/data_source.go +++ b/internal/services/api_shield_operation/data_source.go @@ -64,7 +64,7 @@ func (d *APIShieldOperationDataSource) Read(ctx context.Context, req datasource. return } - env := APIShieldOperationResultListDataSourceEnvelope{} + env := APIShieldOperationsResultListDataSourceEnvelope{} page, err := d.client.APIGateway.Operations.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) diff --git a/internal/services/api_shield_operation/data_source_model.go b/internal/services/api_shield_operation/data_source_model.go index b2aee6b53f..da6a9a63b6 100644 --- a/internal/services/api_shield_operation/data_source_model.go +++ b/internal/services/api_shield_operation/data_source_model.go @@ -18,10 +18,6 @@ type APIShieldOperationResultDataSourceEnvelope struct { Result APIShieldOperationDataSourceModel `json:"result,computed"` } -type APIShieldOperationResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[APIShieldOperationDataSourceModel] `json:"result,computed"` -} - type APIShieldOperationDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` OperationID types.String `tfsdk:"operation_id" path:"operation_id,computed_optional"` diff --git a/internal/services/api_token/data_source.go b/internal/services/api_token/data_source.go index 548080f7fb..7d634096de 100644 --- a/internal/services/api_token/data_source.go +++ b/internal/services/api_token/data_source.go @@ -64,7 +64,7 @@ func (d *APITokenDataSource) Read(ctx context.Context, req datasource.ReadReques return } - env := APITokenResultListDataSourceEnvelope{} + env := APITokensResultListDataSourceEnvelope{} page, err := d.client.User.Tokens.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *APITokenDataSource) Read(ctx context.Context, req datasource.ReadReques } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.TokenID = ts[0].TokenID + data.TokenID = ts[0].ID } res := new(http.Response) diff --git a/internal/services/api_token/data_source_model.go b/internal/services/api_token/data_source_model.go index 2dacd5d43a..13b74db03c 100644 --- a/internal/services/api_token/data_source_model.go +++ b/internal/services/api_token/data_source_model.go @@ -17,10 +17,6 @@ type APITokenResultDataSourceEnvelope struct { Result APITokenDataSourceModel `json:"result,computed"` } -type APITokenResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[APITokenDataSourceModel] `json:"result,computed"` -} - type APITokenDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TokenID types.String `tfsdk:"token_id" path:"token_id,optional"` diff --git a/internal/services/api_token/data_source_test.go b/internal/services/api_token/data_source_test.go index 19a2b7040e..95183afee5 100644 --- a/internal/services/api_token/data_source_test.go +++ b/internal/services/api_token/data_source_test.go @@ -1,4 +1,4 @@ -package api_token +package api_token_test import ( "fmt" diff --git a/internal/services/api_token_permissions_groups/data_source.go b/internal/services/api_token_permissions_groups/data_source.go new file mode 100644 index 0000000000..30464a30d5 --- /dev/null +++ b/internal/services/api_token_permissions_groups/data_source.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package api_token_permissions_groups + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type APITokenPermissionsGroupsDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*APITokenPermissionsGroupsDataSource)(nil) + +func NewAPITokenPermissionsGroupsDataSource() datasource.DataSource { + return &APITokenPermissionsGroupsDataSource{} +} + +func (d *APITokenPermissionsGroupsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_api_token_permissions_groups" +} + +func (d *APITokenPermissionsGroupsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *APITokenPermissionsGroupsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *APITokenPermissionsGroupsDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := APITokenPermissionsGroupsResultDataSourceEnvelope{*data} + _, err := d.client.Accounts.Tokens.PermissionGroups.Get( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/api_token_permissions_groups/data_source_model.go b/internal/services/api_token_permissions_groups/data_source_model.go new file mode 100644 index 0000000000..4435e5d4da --- /dev/null +++ b/internal/services/api_token_permissions_groups/data_source_model.go @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package api_token_permissions_groups + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/accounts" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type APITokenPermissionsGroupsResultDataSourceEnvelope struct { + Result APITokenPermissionsGroupsDataSourceModel `json:"result,computed"` +} + +type APITokenPermissionsGroupsDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + ID types.String `tfsdk:"id" json:"id,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + Scopes customfield.List[types.String] `tfsdk:"scopes" json:"scopes,computed"` +} + +func (m *APITokenPermissionsGroupsDataSourceModel) toReadParams(_ context.Context) (params accounts.TokenPermissionGroupGetParams, diags diag.Diagnostics) { + params = accounts.TokenPermissionGroupGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} diff --git a/internal/services/api_token_permissions_groups/data_source_schema.go b/internal/services/api_token_permissions_groups/data_source_schema.go new file mode 100644 index 0000000000..1502317335 --- /dev/null +++ b/internal/services/api_token_permissions_groups/data_source_schema.go @@ -0,0 +1,60 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package api_token_permissions_groups + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*APITokenPermissionsGroupsDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account identifier tag.", + Required: true, + }, + "id": schema.StringAttribute{ + Description: "Public ID.", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Permission Group Name", + Computed: true, + }, + "scopes": schema.ListAttribute{ + Description: "Resources to which the Permission Group is scoped", + Computed: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "com.cloudflare.api.account", + "com.cloudflare.api.account.zone", + "com.cloudflare.api.user", + "com.cloudflare.edge.r2.bucket", + ), + ), + }, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, + } +} + +func (d *APITokenPermissionsGroupsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *APITokenPermissionsGroupsDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/api_token_permissions_groups/data_source_schema_test.go b/internal/services/api_token_permissions_groups/data_source_schema_test.go new file mode 100644 index 0000000000..6c7133ba32 --- /dev/null +++ b/internal/services/api_token_permissions_groups/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package api_token_permissions_groups_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/api_token_permissions_groups" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestAPITokenPermissionsGroupsDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*api_token_permissions_groups.APITokenPermissionsGroupsDataSourceModel)(nil) + schema := api_token_permissions_groups.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/api_token_permissions_groups/list_data_source_model.go b/internal/services/api_token_permissions_groups/list_data_source_model.go index f6a6fecaf5..08954dfc7d 100644 --- a/internal/services/api_token_permissions_groups/list_data_source_model.go +++ b/internal/services/api_token_permissions_groups/list_data_source_model.go @@ -31,4 +31,7 @@ func (m *APITokenPermissionsGroupsListDataSourceModel) toListParams(_ context.Co } type APITokenPermissionsGroupsListResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + Scopes customfield.List[types.String] `tfsdk:"scopes" json:"scopes,computed"` } diff --git a/internal/services/api_token_permissions_groups/list_data_source_schema.go b/internal/services/api_token_permissions_groups/list_data_source_schema.go index 8aa925d2da..95088e92fb 100644 --- a/internal/services/api_token_permissions_groups/list_data_source_schema.go +++ b/internal/services/api_token_permissions_groups/list_data_source_schema.go @@ -7,9 +7,12 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*APITokenPermissionsGroupsListDataSource)(nil) @@ -33,7 +36,32 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectListType[APITokenPermissionsGroupsListResultDataSourceModel](ctx), NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{}, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Public ID.", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Permission Group Name", + Computed: true, + }, + "scopes": schema.ListAttribute{ + Description: "Resources to which the Permission Group is scoped", + Computed: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "com.cloudflare.api.account", + "com.cloudflare.api.account.zone", + "com.cloudflare.api.user", + "com.cloudflare.edge.r2.bucket", + ), + ), + }, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, }, }, }, diff --git a/internal/services/authenticated_origin_pulls/model.go b/internal/services/authenticated_origin_pulls/model.go index 615983760a..c222b0d27c 100644 --- a/internal/services/authenticated_origin_pulls/model.go +++ b/internal/services/authenticated_origin_pulls/model.go @@ -24,7 +24,9 @@ type AuthenticatedOriginPullsModel struct { CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` ExpiresOn timetypes.RFC3339 `tfsdk:"expires_on" json:"expires_on,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` Issuer types.String `tfsdk:"issuer" json:"issuer,computed"` + PrivateKey types.String `tfsdk:"private_key" json:"private_key,computed"` SerialNumber types.String `tfsdk:"serial_number" json:"serial_number,computed"` Signature types.String `tfsdk:"signature" json:"signature,computed"` Status types.String `tfsdk:"status" json:"status,computed"` diff --git a/internal/services/authenticated_origin_pulls/schema.go b/internal/services/authenticated_origin_pulls/schema.go index 363a9678f4..624de3beaf 100644 --- a/internal/services/authenticated_origin_pulls/schema.go +++ b/internal/services/authenticated_origin_pulls/schema.go @@ -97,10 +97,18 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: timetypes.RFC3339Type{}, }, + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, "issuer": schema.StringAttribute{ Description: "The certificate authority that issued the certificate.", Computed: true, }, + "private_key": schema.StringAttribute{ + Description: "The hostname certificate's private key.", + Computed: true, + }, "serial_number": schema.StringAttribute{ Description: "The serial number on the uploaded certificate.", Computed: true, diff --git a/internal/services/botnet_feed_config_asn/data_source.go b/internal/services/botnet_feed_config_asn/data_source.go new file mode 100644 index 0000000000..db79ec5481 --- /dev/null +++ b/internal/services/botnet_feed_config_asn/data_source.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package botnet_feed_config_asn + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type BotnetFeedConfigASNDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*BotnetFeedConfigASNDataSource)(nil) + +func NewBotnetFeedConfigASNDataSource() datasource.DataSource { + return &BotnetFeedConfigASNDataSource{} +} + +func (d *BotnetFeedConfigASNDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_botnet_feed_config_asn" +} + +func (d *BotnetFeedConfigASNDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *BotnetFeedConfigASNDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *BotnetFeedConfigASNDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := BotnetFeedConfigASNResultDataSourceEnvelope{*data} + _, err := d.client.BotnetFeed.Configs.ASN.Get( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/botnet_feed_config_asn/data_source_model.go b/internal/services/botnet_feed_config_asn/data_source_model.go new file mode 100644 index 0000000000..efeddc7023 --- /dev/null +++ b/internal/services/botnet_feed_config_asn/data_source_model.go @@ -0,0 +1,29 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package botnet_feed_config_asn + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/botnet_feed" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type BotnetFeedConfigASNResultDataSourceEnvelope struct { + Result BotnetFeedConfigASNDataSourceModel `json:"result,computed"` +} + +type BotnetFeedConfigASNDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + ASN types.Int64 `tfsdk:"asn" json:"asn,computed"` +} + +func (m *BotnetFeedConfigASNDataSourceModel) toReadParams(_ context.Context) (params botnet_feed.ConfigASNGetParams, diags diag.Diagnostics) { + params = botnet_feed.ConfigASNGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} diff --git a/internal/services/botnet_feed_config_asn/data_source_schema.go b/internal/services/botnet_feed_config_asn/data_source_schema.go new file mode 100644 index 0000000000..050d2a73eb --- /dev/null +++ b/internal/services/botnet_feed_config_asn/data_source_schema.go @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package botnet_feed_config_asn + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +var _ datasource.DataSourceWithConfigValidators = (*BotnetFeedConfigASNDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "asn": schema.Int64Attribute{ + Computed: true, + }, + }, + } +} + +func (d *BotnetFeedConfigASNDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *BotnetFeedConfigASNDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/botnet_feed_config_asn/data_source_schema_test.go b/internal/services/botnet_feed_config_asn/data_source_schema_test.go new file mode 100644 index 0000000000..9dba5c6faf --- /dev/null +++ b/internal/services/botnet_feed_config_asn/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package botnet_feed_config_asn_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/botnet_feed_config_asn" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestBotnetFeedConfigASNDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*botnet_feed_config_asn.BotnetFeedConfigASNDataSourceModel)(nil) + schema := botnet_feed_config_asn.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/byo_ip_prefix/data_source_model.go b/internal/services/byo_ip_prefix/data_source_model.go index de22311265..57a840fc2f 100644 --- a/internal/services/byo_ip_prefix/data_source_model.go +++ b/internal/services/byo_ip_prefix/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/addressing" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ByoIPPrefixResultDataSourceEnvelope struct { Result ByoIPPrefixDataSourceModel `json:"result,computed"` } -type ByoIPPrefixResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ByoIPPrefixDataSourceModel] `json:"result,computed"` -} - type ByoIPPrefixDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PrefixID types.String `tfsdk:"prefix_id" path:"prefix_id,optional"` diff --git a/internal/services/cloud_connector_rules/model.go b/internal/services/cloud_connector_rules/model.go index e0cdbdda45..8d5cece856 100644 --- a/internal/services/cloud_connector_rules/model.go +++ b/internal/services/cloud_connector_rules/model.go @@ -4,6 +4,7 @@ package cloud_connector_rules import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -12,8 +13,14 @@ type CloudConnectorRulesResultEnvelope struct { } type CloudConnectorRulesModel struct { - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Rules *[]*CloudConnectorRulesRulesModel `tfsdk:"rules" json:"rules,required"` + ID types.String `tfsdk:"id" json:"id,computed"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Rules *[]*CloudConnectorRulesRulesModel `tfsdk:"rules" json:"rules,required"` + CloudProvider types.String `tfsdk:"cloud_provider" json:"provider,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Expression types.String `tfsdk:"expression" json:"expression,computed"` + Parameters customfield.NestedObject[CloudConnectorRulesParametersModel] `tfsdk:"parameters" json:"parameters,computed"` } func (m CloudConnectorRulesModel) MarshalJSON() (data []byte, err error) { @@ -36,3 +43,7 @@ type CloudConnectorRulesRulesModel struct { type CloudConnectorRulesRulesParametersModel struct { Host types.String `tfsdk:"host" json:"host,optional"` } + +type CloudConnectorRulesParametersModel struct { + Host types.String `tfsdk:"host" json:"host,computed"` +} diff --git a/internal/services/cloud_connector_rules/resource.go b/internal/services/cloud_connector_rules/resource.go index 56ebcda80d..c1dc08ec6d 100644 --- a/internal/services/cloud_connector_rules/resource.go +++ b/internal/services/cloud_connector_rules/resource.go @@ -119,7 +119,7 @@ func (r *CloudConnectorRulesResource) Update(ctx context.Context, req resource.U _, err = r.client.CloudConnector.Rules.Update( ctx, cloud_connector.RuleUpdateParams{ - ZoneID: cloudflare.F(data.ZoneID.ValueString()), + ZoneID: cloudflare.F(data.ID.ValueString()), }, option.WithRequestBody("application/json", dataBytes), option.WithResponseBodyInto(&res), diff --git a/internal/services/cloud_connector_rules/schema.go b/internal/services/cloud_connector_rules/schema.go index dc220074e1..ddf53604b6 100644 --- a/internal/services/cloud_connector_rules/schema.go +++ b/internal/services/cloud_connector_rules/schema.go @@ -5,6 +5,7 @@ package cloud_connector_rules import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -19,6 +20,10 @@ var _ resource.ResourceWithConfigValidators = (*CloudConnectorRulesResource)(nil func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, + }, "zone_id": schema.StringAttribute{ Description: "Identifier", Required: true, @@ -67,6 +72,38 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "cloud_provider": schema.StringAttribute{ + Description: "Cloud Provider type", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "aws_s3", + "r2", + "gcp_storage", + "azure_storage", + ), + }, + }, + "description": schema.StringAttribute{ + Computed: true, + }, + "enabled": schema.BoolAttribute{ + Computed: true, + }, + "expression": schema.StringAttribute{ + Computed: true, + }, + "parameters": schema.SingleNestedAttribute{ + Description: "Parameters of Cloud Connector Rule", + Computed: true, + CustomType: customfield.NewNestedObjectType[CloudConnectorRulesParametersModel](ctx), + Attributes: map[string]schema.Attribute{ + "host": schema.StringAttribute{ + Description: "Host to perform Cloud Connection to", + Computed: true, + }, + }, + }, }, } } diff --git a/internal/services/cloudforce_one_request/data_source_model.go b/internal/services/cloudforce_one_request/data_source_model.go index 9fca5acb67..d56ea5f3d8 100644 --- a/internal/services/cloudforce_one_request/data_source_model.go +++ b/internal/services/cloudforce_one_request/data_source_model.go @@ -6,7 +6,6 @@ import ( "context" "github.com/cloudflare/cloudflare-go/v4/cloudforce_one" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -16,10 +15,6 @@ type CloudforceOneRequestResultDataSourceEnvelope struct { Result CloudforceOneRequestDataSourceModel `json:"result,computed"` } -type CloudforceOneRequestResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[CloudforceOneRequestDataSourceModel] `json:"result,computed"` -} - type CloudforceOneRequestDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,optional"` diff --git a/internal/services/cloudforce_one_request_asset/data_source_model.go b/internal/services/cloudforce_one_request_asset/data_source_model.go index fc4b243365..90ff8af5b9 100644 --- a/internal/services/cloudforce_one_request_asset/data_source_model.go +++ b/internal/services/cloudforce_one_request_asset/data_source_model.go @@ -3,6 +3,7 @@ package cloudforce_one_request_asset import ( + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -11,7 +12,12 @@ type CloudforceOneRequestAssetResultDataSourceEnvelope struct { } type CloudforceOneRequestAssetDataSourceModel struct { - AccountIdentifier types.String `tfsdk:"account_identifier" path:"account_identifier,required"` - AssetIdentifer types.String `tfsdk:"asset_identifer" path:"asset_identifer,required"` - RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,required"` + AccountIdentifier types.String `tfsdk:"account_identifier" path:"account_identifier,required"` + AssetIdentifer types.String `tfsdk:"asset_identifer" path:"asset_identifer,required"` + RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,required"` + Created timetypes.RFC3339 `tfsdk:"created" json:"created,computed" format:"date-time"` + Description types.String `tfsdk:"description" json:"description,computed"` + FileType types.String `tfsdk:"file_type" json:"file_type,computed"` + ID types.Int64 `tfsdk:"id" json:"id,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` } diff --git a/internal/services/cloudforce_one_request_asset/data_source_schema.go b/internal/services/cloudforce_one_request_asset/data_source_schema.go index e0bf018ecc..d7b460b8eb 100644 --- a/internal/services/cloudforce_one_request_asset/data_source_schema.go +++ b/internal/services/cloudforce_one_request_asset/data_source_schema.go @@ -5,6 +5,7 @@ package cloudforce_one_request_asset import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -26,6 +27,27 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "UUID", Required: true, }, + "created": schema.StringAttribute{ + Description: "Asset creation time", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "description": schema.StringAttribute{ + Description: "Asset description", + Computed: true, + }, + "file_type": schema.StringAttribute{ + Description: "Asset file type", + Computed: true, + }, + "id": schema.Int64Attribute{ + Description: "Asset ID", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Asset name", + Computed: true, + }, }, } } diff --git a/internal/services/cloudforce_one_request_asset/model.go b/internal/services/cloudforce_one_request_asset/model.go index d04633dafa..36575cffc2 100644 --- a/internal/services/cloudforce_one_request_asset/model.go +++ b/internal/services/cloudforce_one_request_asset/model.go @@ -13,16 +13,15 @@ type CloudforceOneRequestAssetResultEnvelope struct { } type CloudforceOneRequestAssetModel struct { + ID types.Int64 `tfsdk:"id" json:"id,computed"` AccountIdentifier types.String `tfsdk:"account_identifier" path:"account_identifier,required"` RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,required"` - AssetIdentifer types.String `tfsdk:"asset_identifer" path:"asset_identifer,optional"` Page types.Int64 `tfsdk:"page" json:"page,required"` PerPage types.Int64 `tfsdk:"per_page" json:"per_page,required"` Source types.String `tfsdk:"source" json:"source,optional"` Created timetypes.RFC3339 `tfsdk:"created" json:"created,computed" format:"date-time"` Description types.String `tfsdk:"description" json:"description,computed"` FileType types.String `tfsdk:"file_type" json:"file_type,computed"` - ID types.Int64 `tfsdk:"id" json:"id,computed"` Name types.String `tfsdk:"name" json:"name,computed"` } diff --git a/internal/services/cloudforce_one_request_asset/resource.go b/internal/services/cloudforce_one_request_asset/resource.go index 9460d92adb..04f491ca64 100644 --- a/internal/services/cloudforce_one_request_asset/resource.go +++ b/internal/services/cloudforce_one_request_asset/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/cloudforce_one" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*CloudforceOneRequestAssetResource)(nil) var _ resource.ResourceWithModifyPlan = (*CloudforceOneRequestAssetResource)(nil) +var _ resource.ResourceWithImportState = (*CloudforceOneRequestAssetResource)(nil) func NewResource() resource.Resource { return &CloudforceOneRequestAssetResource{} @@ -120,7 +123,7 @@ func (r *CloudforceOneRequestAssetResource) Update(ctx context.Context, req reso ctx, data.AccountIdentifier.ValueString(), data.RequestIdentifier.ValueString(), - data.AssetIdentifer.ValueString(), + fmt.Sprintf("%d", data.ID.ValueInt64()), cloudforce_one.RequestAssetUpdateParams{}, option.WithRequestBody("application/json", dataBytes), option.WithResponseBodyInto(&res), @@ -156,7 +159,7 @@ func (r *CloudforceOneRequestAssetResource) Read(ctx context.Context, req resour ctx, data.AccountIdentifier.ValueString(), data.RequestIdentifier.ValueString(), - data.AssetIdentifer.ValueString(), + fmt.Sprintf("%d", data.ID.ValueInt64()), option.WithResponseBodyInto(&res), option.WithMiddleware(logging.Middleware(ctx)), ) @@ -193,7 +196,7 @@ func (r *CloudforceOneRequestAssetResource) Delete(ctx context.Context, req reso ctx, data.AccountIdentifier.ValueString(), data.RequestIdentifier.ValueString(), - data.AssetIdentifer.ValueString(), + fmt.Sprintf("%d", data.ID.ValueInt64()), option.WithMiddleware(logging.Middleware(ctx)), ) if err != nil { @@ -204,6 +207,53 @@ func (r *CloudforceOneRequestAssetResource) Delete(ctx context.Context, req reso resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *CloudforceOneRequestAssetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *CloudforceOneRequestAssetModel = new(CloudforceOneRequestAssetModel) + + path_account_identifier := "" + path_request_identifier := "" + path_asset_identifer := int64(0) + diags := importpath.ParseImportID( + req.ID, + "//", + &path_account_identifier, + &path_request_identifier, + &path_asset_identifer, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountIdentifier = types.StringValue(path_account_identifier) + data.RequestIdentifier = types.StringValue(path_request_identifier) + data.ID = types.Int64Value(path_asset_identifer) + + res := new(http.Response) + env := CloudforceOneRequestAssetResultEnvelope{*data} + _, err := r.client.CloudforceOne.Requests.Assets.Get( + ctx, + path_account_identifier, + path_request_identifier, + fmt.Sprintf("%d", path_asset_identifer), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *CloudforceOneRequestAssetResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/cloudforce_one_request_asset/schema.go b/internal/services/cloudforce_one_request_asset/schema.go index 855601ff3e..c5000e50a5 100644 --- a/internal/services/cloudforce_one_request_asset/schema.go +++ b/internal/services/cloudforce_one_request_asset/schema.go @@ -18,6 +18,11 @@ var _ resource.ResourceWithConfigValidators = (*CloudforceOneRequestAssetResourc func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Description: "Asset ID", + Computed: true, + PlanModifiers: []planmodifier.Int64{int64planmodifier.UseStateForUnknown()}, + }, "account_identifier": schema.StringAttribute{ Description: "Identifier", Required: true, @@ -28,11 +33,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "asset_identifer": schema.StringAttribute{ - Description: "UUID", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "page": schema.Int64Attribute{ Description: "Page number of results", Required: true, @@ -60,10 +60,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Asset file type", Computed: true, }, - "id": schema.Int64Attribute{ - Description: "Asset ID", - Computed: true, - }, "name": schema.StringAttribute{ Description: "Asset name", Computed: true, diff --git a/internal/services/cloudforce_one_request_message/data_source_model.go b/internal/services/cloudforce_one_request_message/data_source_model.go index 9a66bd5b5b..435f116eee 100644 --- a/internal/services/cloudforce_one_request_message/data_source_model.go +++ b/internal/services/cloudforce_one_request_message/data_source_model.go @@ -6,6 +6,7 @@ import ( "context" "github.com/cloudflare/cloudflare-go/v4/cloudforce_one" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -15,8 +16,14 @@ type CloudforceOneRequestMessageResultDataSourceEnvelope struct { } type CloudforceOneRequestMessageDataSourceModel struct { - AccountIdentifier types.String `tfsdk:"account_identifier" path:"account_identifier,required"` - RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,required"` + AccountIdentifier types.String `tfsdk:"account_identifier" path:"account_identifier,required"` + RequestIdentifier types.String `tfsdk:"request_identifier" path:"request_identifier,required"` + Author types.String `tfsdk:"author" json:"author,computed"` + Content types.String `tfsdk:"content" json:"content,computed"` + Created timetypes.RFC3339 `tfsdk:"created" json:"created,computed" format:"date-time"` + ID types.Int64 `tfsdk:"id" json:"id,computed"` + IsFollowOnRequest types.Bool `tfsdk:"is_follow_on_request" json:"is_follow_on_request,computed"` + Updated timetypes.RFC3339 `tfsdk:"updated" json:"updated,computed" format:"date-time"` } func (m *CloudforceOneRequestMessageDataSourceModel) toReadParams(_ context.Context) (params cloudforce_one.RequestMessageGetParams, diags diag.Diagnostics) { diff --git a/internal/services/cloudforce_one_request_message/data_source_schema.go b/internal/services/cloudforce_one_request_message/data_source_schema.go index 7f53345815..e0ab4af440 100644 --- a/internal/services/cloudforce_one_request_message/data_source_schema.go +++ b/internal/services/cloudforce_one_request_message/data_source_schema.go @@ -5,6 +5,7 @@ package cloudforce_one_request_message import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -22,6 +23,32 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "UUID", Required: true, }, + "author": schema.StringAttribute{ + Description: "Author of message", + Computed: true, + }, + "content": schema.StringAttribute{ + Description: "Content of message", + Computed: true, + }, + "created": schema.StringAttribute{ + Description: "Message creation time", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "id": schema.Int64Attribute{ + Description: "Message ID", + Computed: true, + }, + "is_follow_on_request": schema.BoolAttribute{ + Description: "Whether the message is a follow-on request", + Computed: true, + }, + "updated": schema.StringAttribute{ + Description: "Message last updated time", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, }, } } diff --git a/internal/services/cloudforce_one_request_message/resource.go b/internal/services/cloudforce_one_request_message/resource.go index 8457e0ffec..141aa5f495 100644 --- a/internal/services/cloudforce_one_request_message/resource.go +++ b/internal/services/cloudforce_one_request_message/resource.go @@ -147,38 +147,38 @@ func (r *CloudforceOneRequestMessageResource) Update(ctx context.Context, req re func (r *CloudforceOneRequestMessageResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data *CloudforceOneRequestMessageModel -// resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - -// if resp.Diagnostics.HasError() { -// return -// } - -// res := new(http.Response) -// env := CloudforceOneRequestMessageResultEnvelope{*data} -// _, err := r.client.CloudforceOne.Requests.Message.Get( -// ctx, -// data.AccountIdentifier.ValueString(), -// data.ID.ValueInt64(), -// cloudforce_one.RequestMessageGetParams{}, -// option.WithResponseBodyInto(&res), -// option.WithMiddleware(logging.Middleware(ctx)), -// ) -// if res != nil && res.StatusCode == 404 { -// resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") -// resp.State.RemoveResource(ctx) -// return -// } -// if err != nil { -// resp.Diagnostics.AddError("failed to make http request", err.Error()) -// return -// } -// bytes, _ := io.ReadAll(res.Body) -// err = apijson.UnmarshalComputed(bytes, &env) -// if err != nil { -// resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) -// return -// } -// data = &env.Result + // resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + // if resp.Diagnostics.HasError() { + // return + // } + + // res := new(http.Response) + // env := CloudforceOneRequestMessageResultEnvelope{*data} + // _, err := r.client.CloudforceOne.Requests.Message.Get( + // ctx, + // data.AccountIdentifier.ValueString(), + // data.ID.ValueInt64(), + // cloudforce_one.RequestMessageGetParams{}, + // option.WithResponseBodyInto(&res), + // option.WithMiddleware(logging.Middleware(ctx)), + // ) + // if res != nil && res.StatusCode == 404 { + // resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + // resp.State.RemoveResource(ctx) + // return + // } + // if err != nil { + // resp.Diagnostics.AddError("failed to make http request", err.Error()) + // return + // } + // bytes, _ := io.ReadAll(res.Body) + // err = apijson.UnmarshalComputed(bytes, &env) + // if err != nil { + // resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + // return + // } + // data = &env.Result resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/services/content_scanning_expression/model.go b/internal/services/content_scanning_expression/model.go index 6c5582f5d0..c54e0fc699 100644 --- a/internal/services/content_scanning_expression/model.go +++ b/internal/services/content_scanning_expression/model.go @@ -12,9 +12,10 @@ type ContentScanningExpressionResultEnvelope struct { } type ContentScanningExpressionModel struct { - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - ExpressionID types.String `tfsdk:"expression_id" path:"expression_id,optional"` - Body *[]*ContentScanningExpressionBodyModel `tfsdk:"body" json:"body,required"` + ID types.String `tfsdk:"id" json:"id,computed"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Body *[]*ContentScanningExpressionBodyModel `tfsdk:"body" json:"body,required"` + Payload types.String `tfsdk:"payload" json:"payload,computed"` } func (m ContentScanningExpressionModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/content_scanning_expression/resource.go b/internal/services/content_scanning_expression/resource.go index 8d2b23ad3b..2cbf2f068f 100644 --- a/internal/services/content_scanning_expression/resource.go +++ b/internal/services/content_scanning_expression/resource.go @@ -119,7 +119,7 @@ func (r *ContentScanningExpressionResource) Update(ctx context.Context, req reso _, err = r.client.ContentScanning.Payloads.New( ctx, content_scanning.PayloadNewParams{ - ZoneID: cloudflare.F(data.ZoneID.ValueString()), + ZoneID: cloudflare.F(data.ID.ValueString()), }, option.WithRequestBody("application/json", dataBytes), option.WithResponseBodyInto(&res), @@ -155,7 +155,7 @@ func (r *ContentScanningExpressionResource) Delete(ctx context.Context, req reso _, err := r.client.ContentScanning.Payloads.Delete( ctx, - data.ExpressionID.ValueString(), + data.ID.ValueString(), content_scanning.PayloadDeleteParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, diff --git a/internal/services/content_scanning_expression/schema.go b/internal/services/content_scanning_expression/schema.go index f4f19f5d9f..c599671de3 100644 --- a/internal/services/content_scanning_expression/schema.go +++ b/internal/services/content_scanning_expression/schema.go @@ -17,16 +17,16 @@ var _ resource.ResourceWithConfigValidators = (*ContentScanningExpressionResourc func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique ID for this custom scan expression", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, + }, "zone_id": schema.StringAttribute{ Description: "Identifier", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "expression_id": schema.StringAttribute{ - Description: "Identifier", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "body": schema.ListNestedAttribute{ Required: true, NestedObject: schema.NestedAttributeObject{ @@ -39,6 +39,10 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "payload": schema.StringAttribute{ + Description: "Ruleset expression to use in matching content objects", + Computed: true, + }, }, } } diff --git a/internal/services/custom_hostname/data_source.go b/internal/services/custom_hostname/data_source.go index abcbd52973..d78e450d6b 100644 --- a/internal/services/custom_hostname/data_source.go +++ b/internal/services/custom_hostname/data_source.go @@ -64,7 +64,7 @@ func (d *CustomHostnameDataSource) Read(ctx context.Context, req datasource.Read return } - env := CustomHostnameResultListDataSourceEnvelope{} + env := CustomHostnamesResultListDataSourceEnvelope{} page, err := d.client.CustomHostnames.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *CustomHostnameDataSource) Read(ctx context.Context, req datasource.Read } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.CustomHostnameID = ts[0].CustomHostnameID + data.CustomHostnameID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/custom_hostname/data_source_model.go b/internal/services/custom_hostname/data_source_model.go index ebc81b67ef..de9d7cc61d 100644 --- a/internal/services/custom_hostname/data_source_model.go +++ b/internal/services/custom_hostname/data_source_model.go @@ -17,10 +17,6 @@ type CustomHostnameResultDataSourceEnvelope struct { Result CustomHostnameDataSourceModel `json:"result,computed"` } -type CustomHostnameResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[CustomHostnameDataSourceModel] `json:"result,computed"` -} - type CustomHostnameDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CustomHostnameID types.String `tfsdk:"custom_hostname_id" path:"custom_hostname_id,optional"` diff --git a/internal/services/custom_hostname/model.go b/internal/services/custom_hostname/model.go index 657e58a615..d970aeeeca 100644 --- a/internal/services/custom_hostname/model.go +++ b/internal/services/custom_hostname/model.go @@ -37,15 +37,21 @@ func (m CustomHostnameModel) MarshalJSONForUpdate(state CustomHostnameModel) (da } type CustomHostnameSSLModel struct { - BundleMethod types.String `tfsdk:"bundle_method" json:"bundle_method,computed_optional"` - CertificateAuthority types.String `tfsdk:"certificate_authority" json:"certificate_authority,computed_optional"` - CloudflareBranding types.Bool `tfsdk:"cloudflare_branding" json:"cloudflare_branding,optional"` - CustomCertificate types.String `tfsdk:"custom_certificate" json:"custom_certificate,optional"` - CustomKey types.String `tfsdk:"custom_key" json:"custom_key,optional"` - Method types.String `tfsdk:"method" json:"method,optional"` - Settings *CustomHostnameSSLSettingsModel `tfsdk:"settings" json:"settings,optional"` - Type types.String `tfsdk:"type" json:"type,optional"` - Wildcard types.Bool `tfsdk:"wildcard" json:"wildcard,optional"` + BundleMethod types.String `tfsdk:"bundle_method" json:"bundle_method,computed_optional"` + CertificateAuthority types.String `tfsdk:"certificate_authority" json:"certificate_authority,computed_optional"` + CloudflareBranding types.Bool `tfsdk:"cloudflare_branding" json:"cloudflare_branding,optional"` + CustomCERTBundle *[]*CustomHostnameSSLCustomCERTBundleModel `tfsdk:"custom_cert_bundle" json:"custom_cert_bundle,optional"` + CustomCertificate types.String `tfsdk:"custom_certificate" json:"custom_certificate,optional"` + CustomKey types.String `tfsdk:"custom_key" json:"custom_key,optional"` + Method types.String `tfsdk:"method" json:"method,optional"` + Settings *CustomHostnameSSLSettingsModel `tfsdk:"settings" json:"settings,optional"` + Type types.String `tfsdk:"type" json:"type,optional"` + Wildcard types.Bool `tfsdk:"wildcard" json:"wildcard,optional"` +} + +type CustomHostnameSSLCustomCERTBundleModel struct { + CustomCertificate types.String `tfsdk:"custom_certificate" json:"custom_certificate,required"` + CustomKey types.String `tfsdk:"custom_key" json:"custom_key,required"` } type CustomHostnameSSLSettingsModel struct { diff --git a/internal/services/custom_hostname/schema.go b/internal/services/custom_hostname/schema.go index 6c95865045..e71372d94c 100644 --- a/internal/services/custom_hostname/schema.go +++ b/internal/services/custom_hostname/schema.go @@ -71,6 +71,22 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Whether or not to add Cloudflare Branding for the order. This will add a subdomain of sni.cloudflaressl.com as the Common Name if set to true", Optional: true, }, + "custom_cert_bundle": schema.ListNestedAttribute{ + Description: "Array of custom certificate and key pairs (1 or 2 pairs allowed)", + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "custom_certificate": schema.StringAttribute{ + Description: "If a custom uploaded certificate is used.", + Required: true, + }, + "custom_key": schema.StringAttribute{ + Description: "The key for a custom uploaded certificate.", + Required: true, + }, + }, + }, + }, "custom_certificate": schema.StringAttribute{ Description: "If a custom uploaded certificate is used.", Optional: true, diff --git a/internal/services/custom_ssl/data_source.go b/internal/services/custom_ssl/data_source.go index 8d4bd32fc8..fce48e1c8d 100644 --- a/internal/services/custom_ssl/data_source.go +++ b/internal/services/custom_ssl/data_source.go @@ -64,7 +64,7 @@ func (d *CustomSSLDataSource) Read(ctx context.Context, req datasource.ReadReque return } - env := CustomSSLResultListDataSourceEnvelope{} + env := CustomSSLsResultListDataSourceEnvelope{} page, err := d.client.CustomCertificates.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *CustomSSLDataSource) Read(ctx context.Context, req datasource.ReadReque } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.CustomCertificateID = ts[0].CustomCertificateID + data.CustomCertificateID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/custom_ssl/data_source_model.go b/internal/services/custom_ssl/data_source_model.go index 45a322598d..b495bbdf02 100644 --- a/internal/services/custom_ssl/data_source_model.go +++ b/internal/services/custom_ssl/data_source_model.go @@ -17,10 +17,6 @@ type CustomSSLResultDataSourceEnvelope struct { Result CustomSSLDataSourceModel `json:"result,computed"` } -type CustomSSLResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[CustomSSLDataSourceModel] `json:"result,computed"` -} - type CustomSSLDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CustomCertificateID types.String `tfsdk:"custom_certificate_id" path:"custom_certificate_id,optional"` diff --git a/internal/services/d1_database/data_source.go b/internal/services/d1_database/data_source.go index 9d54dc4bf3..80de9447f6 100644 --- a/internal/services/d1_database/data_source.go +++ b/internal/services/d1_database/data_source.go @@ -64,7 +64,7 @@ func (d *D1DatabaseDataSource) Read(ctx context.Context, req datasource.ReadRequ return } - env := D1DatabaseResultListDataSourceEnvelope{} + env := D1DatabasesResultListDataSourceEnvelope{} page, err := d.client.D1.Database.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *D1DatabaseDataSource) Read(ctx context.Context, req datasource.ReadRequ } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.DatabaseID = ts[0].DatabaseID + data.DatabaseID = ts[0].UUID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/d1_database/data_source_model.go b/internal/services/d1_database/data_source_model.go index ebd89e1711..bce08b950e 100644 --- a/internal/services/d1_database/data_source_model.go +++ b/internal/services/d1_database/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/d1" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type D1DatabaseResultDataSourceEnvelope struct { Result D1DatabaseDataSourceModel `json:"result,computed"` } -type D1DatabaseResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[D1DatabaseDataSourceModel] `json:"result,computed"` -} - type D1DatabaseDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DatabaseID types.String `tfsdk:"database_id" path:"database_id,optional"` diff --git a/internal/services/d1_database/data_source_schema.go b/internal/services/d1_database/data_source_schema.go index e27f5e32e7..74a2cded23 100644 --- a/internal/services/d1_database/data_source_schema.go +++ b/internal/services/d1_database/data_source_schema.go @@ -18,10 +18,12 @@ func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Computed: true, + Description: "D1 database identifier (UUID).", + Computed: true, }, "database_id": schema.StringAttribute{ - Optional: true, + Description: "D1 database identifier (UUID).", + Optional: true, }, "account_id": schema.StringAttribute{ Description: "Account identifier tag.", @@ -37,13 +39,15 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, }, "name": schema.StringAttribute{ - Computed: true, + Description: "D1 database name.", + Computed: true, }, "num_tables": schema.Float64Attribute{ Computed: true, }, "uuid": schema.StringAttribute{ - Computed: true, + Description: "D1 database identifier (UUID).", + Computed: true, }, "version": schema.StringAttribute{ Computed: true, diff --git a/internal/services/d1_database/list_data_source_schema.go b/internal/services/d1_database/list_data_source_schema.go index 3c7ae24e58..f1e54889f6 100644 --- a/internal/services/d1_database/list_data_source_schema.go +++ b/internal/services/d1_database/list_data_source_schema.go @@ -45,10 +45,12 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { CustomType: timetypes.RFC3339Type{}, }, "name": schema.StringAttribute{ - Computed: true, + Description: "D1 database name.", + Computed: true, }, "uuid": schema.StringAttribute{ - Computed: true, + Description: "D1 database identifier (UUID).", + Computed: true, }, "version": schema.StringAttribute{ Computed: true, diff --git a/internal/services/d1_database/schema.go b/internal/services/d1_database/schema.go index 8f714b7274..6969d2cfba 100644 --- a/internal/services/d1_database/schema.go +++ b/internal/services/d1_database/schema.go @@ -20,10 +20,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ + Description: "D1 database identifier (UUID).", Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, "uuid": schema.StringAttribute{ + Description: "D1 database identifier (UUID).", Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, @@ -33,6 +35,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, "name": schema.StringAttribute{ + Description: "D1 database name.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, diff --git a/internal/services/dns_firewall/data_source_model.go b/internal/services/dns_firewall/data_source_model.go index cc1d2fc400..21119b04f8 100644 --- a/internal/services/dns_firewall/data_source_model.go +++ b/internal/services/dns_firewall/data_source_model.go @@ -17,10 +17,6 @@ type DNSFirewallResultDataSourceEnvelope struct { Result DNSFirewallDataSourceModel `json:"result,computed"` } -type DNSFirewallResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[DNSFirewallDataSourceModel] `json:"result,computed"` -} - type DNSFirewallDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DNSFirewallID types.String `tfsdk:"dns_firewall_id" path:"dns_firewall_id,optional"` diff --git a/internal/services/dns_firewall/model.go b/internal/services/dns_firewall/model.go index cdae4c6e8b..d813d61a61 100644 --- a/internal/services/dns_firewall/model.go +++ b/internal/services/dns_firewall/model.go @@ -16,12 +16,12 @@ type DNSFirewallResultEnvelope struct { type DNSFirewallModel struct { ID types.String `tfsdk:"id" json:"id,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Name types.String `tfsdk:"name" json:"name,required"` + UpstreamIPs *[]types.String `tfsdk:"upstream_ips" json:"upstream_ips,required"` DeprecateAnyRequests types.Bool `tfsdk:"deprecate_any_requests" json:"deprecate_any_requests,optional"` ECSFallback types.Bool `tfsdk:"ecs_fallback" json:"ecs_fallback,optional"` - Name types.String `tfsdk:"name" json:"name,optional"` NegativeCacheTTL types.Float64 `tfsdk:"negative_cache_ttl" json:"negative_cache_ttl,optional"` Ratelimit types.Float64 `tfsdk:"ratelimit" json:"ratelimit,optional"` - UpstreamIPs *[]types.String `tfsdk:"upstream_ips" json:"upstream_ips,optional"` MaximumCacheTTL types.Float64 `tfsdk:"maximum_cache_ttl" json:"maximum_cache_ttl,computed_optional"` MinimumCacheTTL types.Float64 `tfsdk:"minimum_cache_ttl" json:"minimum_cache_ttl,computed_optional"` Retries types.Float64 `tfsdk:"retries" json:"retries,computed_optional"` diff --git a/internal/services/dns_firewall/schema.go b/internal/services/dns_firewall/schema.go index fab62d1bea..f343e87cc1 100644 --- a/internal/services/dns_firewall/schema.go +++ b/internal/services/dns_firewall/schema.go @@ -33,6 +33,14 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, + "name": schema.StringAttribute{ + Description: "DNS Firewall cluster name", + Required: true, + }, + "upstream_ips": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + }, "deprecate_any_requests": schema.BoolAttribute{ Description: "Whether to refuse to answer queries for the ANY type", Optional: true, @@ -41,10 +49,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "Whether to forward client IP (resolver) subnet if no EDNS Client Subnet is sent", Optional: true, }, - "name": schema.StringAttribute{ - Description: "DNS Firewall cluster name", - Optional: true, - }, "negative_cache_ttl": schema.Float64Attribute{ Description: "Negative DNS cache TTL This setting controls how long DNS Firewall should cache negative responses (e.g., NXDOMAIN) from the upstream servers.", Optional: true, @@ -59,10 +63,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { float64validator.Between(100, 1000000000), }, }, - "upstream_ips": schema.ListAttribute{ - Optional: true, - ElementType: types.StringType, - }, "maximum_cache_ttl": schema.Float64Attribute{ Description: "Maximum DNS cache TTL This setting sets an upper bound on DNS TTLs for purposes of caching between DNS Firewall and the upstream servers. Higher TTLs will be decreased to the maximum defined here for caching purposes.", Computed: true, diff --git a/internal/services/dns_record/data_source.go b/internal/services/dns_record/data_source.go index 3372454247..6067eafbb1 100755 --- a/internal/services/dns_record/data_source.go +++ b/internal/services/dns_record/data_source.go @@ -64,7 +64,7 @@ func (d *DNSRecordDataSource) Read(ctx context.Context, req datasource.ReadReque return } - env := DNSRecordResultListDataSourceEnvelope{} + env := DNSRecordsResultListDataSourceEnvelope{} page, err := d.client.DNS.Records.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *DNSRecordDataSource) Read(ctx context.Context, req datasource.ReadReque } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.DNSRecordID = ts[0].DNSRecordID + data.DNSRecordID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/dns_record/data_source_model.go b/internal/services/dns_record/data_source_model.go index b55c334c7b..dc616d8502 100755 --- a/internal/services/dns_record/data_source_model.go +++ b/internal/services/dns_record/data_source_model.go @@ -19,10 +19,6 @@ type DNSRecordResultDataSourceEnvelope struct { Result DNSRecordDataSourceModel `json:"result,computed"` } -type DNSRecordResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[DNSRecordDataSourceModel] `json:"result,computed"` -} - type DNSRecordDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DNSRecordID types.String `tfsdk:"dns_record_id" path:"dns_record_id,optional"` diff --git a/internal/services/dns_record/model.go b/internal/services/dns_record/model.go index 80949737e0..60d935ddf3 100755 --- a/internal/services/dns_record/model.go +++ b/internal/services/dns_record/model.go @@ -44,7 +44,7 @@ func (m DNSRecordModel) MarshalJSONForUpdate(state DNSRecordModel) (data []byte, } type DNSRecordDataModel struct { - Flags types.Dynamic `tfsdk:"flags" json:"flags,optional"` + Flags types.Float64 `tfsdk:"flags" json:"flags,optional"` Tag types.String `tfsdk:"tag" json:"tag,optional"` Value types.String `tfsdk:"value" json:"value,optional"` Algorithm types.Float64 `tfsdk:"algorithm" json:"algorithm,optional"` diff --git a/internal/services/dns_record/schema.go b/internal/services/dns_record/schema.go index 074ce58c99..f488667cf1 100755 --- a/internal/services/dns_record/schema.go +++ b/internal/services/dns_record/schema.go @@ -6,7 +6,6 @@ import ( "context" "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customvalidator" "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" @@ -23,7 +22,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) var _ resource.ResourceWithConfigValidators = (*DNSRecordResource)(nil) @@ -123,11 +121,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, CustomType: customfield.NewNestedObjectType[DNSRecordDataModel](ctx), Attributes: map[string]schema.Attribute{ - "flags": schema.DynamicAttribute{ + "flags": schema.Float64Attribute{ Description: "Flags for the CAA record.", Optional: true, - Validators: []validator.Dynamic{ - customvalidator.AllowedSubtypes(basetypes.Float64Type{}, basetypes.StringType{}), + Validators: []validator.Float64{ + float64validator.Between(0, 255), }, }, "tag": schema.StringAttribute{ diff --git a/internal/services/dns_settings/data_source.go b/internal/services/dns_settings/data_source.go new file mode 100644 index 0000000000..3ef98f4fb3 --- /dev/null +++ b/internal/services/dns_settings/data_source.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type DNSSettingsDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*DNSSettingsDataSource)(nil) + +func NewDNSSettingsDataSource() datasource.DataSource { + return &DNSSettingsDataSource{} +} + +func (d *DNSSettingsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_settings" +} + +func (d *DNSSettingsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *DNSSettingsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *DNSSettingsDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := DNSSettingsResultDataSourceEnvelope{*data} + _, err := d.client.DNS.Settings.Get( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/dns_settings/data_source_model.go b/internal/services/dns_settings/data_source_model.go new file mode 100644 index 0000000000..453c037689 --- /dev/null +++ b/internal/services/dns_settings/data_source_model.go @@ -0,0 +1,65 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type DNSSettingsResultDataSourceEnvelope struct { + Result DNSSettingsDataSourceModel `json:"result,computed"` +} + +type DNSSettingsDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + ZoneDefaults customfield.NestedObject[DNSSettingsZoneDefaultsDataSourceModel] `tfsdk:"zone_defaults" json:"zone_defaults,computed"` +} + +func (m *DNSSettingsDataSourceModel) toReadParams(_ context.Context) (params dns.SettingGetParams, diags diag.Diagnostics) { + params = dns.SettingGetParams{} + + if !m.AccountID.IsNull() { + params.AccountID = cloudflare.F(m.AccountID.ValueString()) + } else { + params.ZoneID = cloudflare.F(m.ZoneID.ValueString()) + } + + return +} + +type DNSSettingsZoneDefaultsDataSourceModel struct { + FlattenAllCNAMEs types.Bool `tfsdk:"flatten_all_cnames" json:"flatten_all_cnames,computed"` + FoundationDNS types.Bool `tfsdk:"foundation_dns" json:"foundation_dns,computed"` + InternalDNS customfield.NestedObject[DNSSettingsZoneDefaultsInternalDNSDataSourceModel] `tfsdk:"internal_dns" json:"internal_dns,computed"` + MultiProvider types.Bool `tfsdk:"multi_provider" json:"multi_provider,computed"` + Nameservers customfield.NestedObject[DNSSettingsZoneDefaultsNameserversDataSourceModel] `tfsdk:"nameservers" json:"nameservers,computed"` + NSTTL types.Float64 `tfsdk:"ns_ttl" json:"ns_ttl,computed"` + SecondaryOverrides types.Bool `tfsdk:"secondary_overrides" json:"secondary_overrides,computed"` + SOA customfield.NestedObject[DNSSettingsZoneDefaultsSOADataSourceModel] `tfsdk:"soa" json:"soa,computed"` + ZoneMode types.String `tfsdk:"zone_mode" json:"zone_mode,computed"` +} + +type DNSSettingsZoneDefaultsInternalDNSDataSourceModel struct { + ReferenceZoneID types.String `tfsdk:"reference_zone_id" json:"reference_zone_id,computed"` +} + +type DNSSettingsZoneDefaultsNameserversDataSourceModel struct { + Type types.String `tfsdk:"type" json:"type,computed"` +} + +type DNSSettingsZoneDefaultsSOADataSourceModel struct { + Expire types.Float64 `tfsdk:"expire" json:"expire,computed"` + MinTTL types.Float64 `tfsdk:"min_ttl" json:"min_ttl,computed"` + MNAME types.String `tfsdk:"mname" json:"mname,computed"` + Refresh types.Float64 `tfsdk:"refresh" json:"refresh,computed"` + Retry types.Float64 `tfsdk:"retry" json:"retry,computed"` + RNAME types.String `tfsdk:"rname" json:"rname,computed"` + TTL types.Float64 `tfsdk:"ttl" json:"ttl,computed"` +} diff --git a/internal/services/dns_settings/data_source_schema.go b/internal/services/dns_settings/data_source_schema.go new file mode 100644 index 0000000000..43924d1c2f --- /dev/null +++ b/internal/services/dns_settings/data_source_schema.go @@ -0,0 +1,163 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*DNSSettingsDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.", + Optional: true, + }, + "zone_id": schema.StringAttribute{ + Description: "The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.", + Optional: true, + }, + "zone_defaults": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "flatten_all_cnames": schema.BoolAttribute{ + Description: "Whether to flatten all CNAME records in the zone. Note that, due to DNS limitations, a CNAME record at the zone apex will always be flattened.", + Computed: true, + }, + "foundation_dns": schema.BoolAttribute{ + Description: "Whether to enable Foundation DNS Advanced Nameservers on the zone.", + Computed: true, + }, + "internal_dns": schema.SingleNestedAttribute{ + Description: "Settings for this internal zone.", + Computed: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsInternalDNSDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "reference_zone_id": schema.StringAttribute{ + Description: "The ID of the zone to fallback to.", + Computed: true, + }, + }, + }, + "multi_provider": schema.BoolAttribute{ + Description: "Whether to enable multi-provider DNS, which causes Cloudflare to activate the zone even when non-Cloudflare NS records exist, and to respect NS records at the zone apex during outbound zone transfers.", + Computed: true, + }, + "nameservers": schema.SingleNestedAttribute{ + Description: "Settings determining the nameservers through which the zone should be available.", + Computed: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsNameserversDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "type": schema.StringAttribute{ + Description: "Nameserver type", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "cloudflare.standard", + "cloudflare.standard.random", + "custom.account", + "custom.tenant", + ), + }, + }, + }, + }, + "ns_ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) of the zone's nameserver (NS) records.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(30, 86400), + }, + }, + "secondary_overrides": schema.BoolAttribute{ + Description: "Allows a Secondary DNS zone to use (proxied) override records and CNAME flattening at the zone apex.", + Computed: true, + }, + "soa": schema.SingleNestedAttribute{ + Description: "Components of the zone's SOA record.", + Computed: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsSOADataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "expire": schema.Float64Attribute{ + Description: "Time in seconds of being unable to query the primary server after which secondary servers should stop serving the zone.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(86400, 2419200), + }, + }, + "min_ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) for negative caching of records within the zone.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(60, 86400), + }, + }, + "mname": schema.StringAttribute{ + Description: "The primary nameserver, which may be used for outbound zone transfers.", + Computed: true, + }, + "refresh": schema.Float64Attribute{ + Description: "Time in seconds after which secondary servers should re-check the SOA record to see if the zone has been updated.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(600, 86400), + }, + }, + "retry": schema.Float64Attribute{ + Description: "Time in seconds after which secondary servers should retry queries after the primary server was unresponsive.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(600, 86400), + }, + }, + "rname": schema.StringAttribute{ + Description: "The email address of the zone administrator, with the first label representing the local part of the email address.", + Computed: true, + }, + "ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) of the SOA record itself.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(300, 86400), + }, + }, + }, + }, + "zone_mode": schema.StringAttribute{ + Description: "Whether the zone mode is a regular or CDN/DNS only zone.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "standard", + "cdn_only", + "dns_only", + ), + }, + }, + }, + }, + }, + } +} + +func (d *DNSSettingsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *DNSSettingsDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.Conflicting(path.MatchRoot("account_id"), path.MatchRoot("zone_id")), + } +} diff --git a/internal/services/dns_settings/data_source_schema_test.go b/internal/services/dns_settings/data_source_schema_test.go new file mode 100644 index 0000000000..19d0c59f08 --- /dev/null +++ b/internal/services/dns_settings/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestDNSSettingsDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*dns_settings.DNSSettingsDataSourceModel)(nil) + schema := dns_settings.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/dns_settings/migrations.go b/internal/services/dns_settings/migrations.go new file mode 100644 index 0000000000..fdff444321 --- /dev/null +++ b/internal/services/dns_settings/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*DNSSettingsResource)(nil) + +func (r *DNSSettingsResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/dns_settings/model.go b/internal/services/dns_settings/model.go new file mode 100644 index 0000000000..c0d4c4301e --- /dev/null +++ b/internal/services/dns_settings/model.go @@ -0,0 +1,57 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type DNSSettingsResultEnvelope struct { + Result DNSSettingsModel `json:"result"` +} + +type DNSSettingsModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + ZoneDefaults customfield.NestedObject[DNSSettingsZoneDefaultsModel] `tfsdk:"zone_defaults" json:"zone_defaults,computed_optional"` +} + +func (m DNSSettingsModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m DNSSettingsModel) MarshalJSONForUpdate(state DNSSettingsModel) (data []byte, err error) { + return apijson.MarshalForPatch(m, state) +} + +type DNSSettingsZoneDefaultsModel struct { + FlattenAllCNAMEs types.Bool `tfsdk:"flatten_all_cnames" json:"flatten_all_cnames,optional"` + FoundationDNS types.Bool `tfsdk:"foundation_dns" json:"foundation_dns,optional"` + InternalDNS customfield.NestedObject[DNSSettingsZoneDefaultsInternalDNSModel] `tfsdk:"internal_dns" json:"internal_dns,computed_optional"` + MultiProvider types.Bool `tfsdk:"multi_provider" json:"multi_provider,optional"` + Nameservers customfield.NestedObject[DNSSettingsZoneDefaultsNameserversModel] `tfsdk:"nameservers" json:"nameservers,computed_optional"` + NSTTL types.Float64 `tfsdk:"ns_ttl" json:"ns_ttl,optional"` + SecondaryOverrides types.Bool `tfsdk:"secondary_overrides" json:"secondary_overrides,optional"` + SOA customfield.NestedObject[DNSSettingsZoneDefaultsSOAModel] `tfsdk:"soa" json:"soa,computed_optional"` + ZoneMode types.String `tfsdk:"zone_mode" json:"zone_mode,optional"` +} + +type DNSSettingsZoneDefaultsInternalDNSModel struct { + ReferenceZoneID types.String `tfsdk:"reference_zone_id" json:"reference_zone_id,optional"` +} + +type DNSSettingsZoneDefaultsNameserversModel struct { + Type types.String `tfsdk:"type" json:"type,required"` +} + +type DNSSettingsZoneDefaultsSOAModel struct { + Expire types.Float64 `tfsdk:"expire" json:"expire,required"` + MinTTL types.Float64 `tfsdk:"min_ttl" json:"min_ttl,required"` + MNAME types.String `tfsdk:"mname" json:"mname,required"` + Refresh types.Float64 `tfsdk:"refresh" json:"refresh,required"` + Retry types.Float64 `tfsdk:"retry" json:"retry,required"` + RNAME types.String `tfsdk:"rname" json:"rname,required"` + TTL types.Float64 `tfsdk:"ttl" json:"ttl,required"` +} diff --git a/internal/services/dns_settings/resource.go b/internal/services/dns_settings/resource.go new file mode 100644 index 0000000000..62b6ad5f8b --- /dev/null +++ b/internal/services/dns_settings/resource.go @@ -0,0 +1,220 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*DNSSettingsResource)(nil) +var _ resource.ResourceWithModifyPlan = (*DNSSettingsResource)(nil) + +func NewResource() resource.Resource { + return &DNSSettingsResource{} +} + +// DNSSettingsResource defines the resource implementation. +type DNSSettingsResource struct { + client *cloudflare.Client +} + +func (r *DNSSettingsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_settings" +} + +func (r *DNSSettingsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *DNSSettingsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *DNSSettingsModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := DNSSettingsResultEnvelope{*data} + params := dns.SettingEditParams{} + + if !data.AccountID.IsNull() { + params.AccountID = cloudflare.F(data.AccountID.ValueString()) + } else { + params.ZoneID = cloudflare.F(data.ZoneID.ValueString()) + } + + _, err = r.client.DNS.Settings.Edit( + ctx, + params, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *DNSSettingsModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *DNSSettingsModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := DNSSettingsResultEnvelope{*data} + params := dns.SettingEditParams{} + + if !data.AccountID.IsNull() { + params.AccountID = cloudflare.F(data.AccountID.ValueString()) + } else { + params.ZoneID = cloudflare.F(data.ZoneID.ValueString()) + } + + _, err = r.client.DNS.Settings.Edit( + ctx, + params, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *DNSSettingsModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := DNSSettingsResultEnvelope{*data} + params := dns.SettingGetParams{} + + if !data.AccountID.IsNull() { + params.AccountID = cloudflare.F(data.AccountID.ValueString()) + } else { + params.ZoneID = cloudflare.F(data.ZoneID.ValueString()) + } + + _, err := r.client.DNS.Settings.Get( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + +} + +func (r *DNSSettingsResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if req.State.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "This resource cannot be destroyed from Terraform. If you create this resource, it will be "+ + "present in the API until manually deleted.", + ) + } + if req.Plan.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "Applying this resource destruction will remove the resource from the Terraform state "+ + "but will not change it in the API. If you would like to destroy or reset this resource "+ + "in the API, refer to the documentation for how to do it manually.", + ) + } +} diff --git a/internal/services/dns_settings/resource_schema_test.go b/internal/services/dns_settings/resource_schema_test.go new file mode 100644 index 0000000000..4321e3e8ce --- /dev/null +++ b/internal/services/dns_settings/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestDNSSettingsModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*dns_settings.DNSSettingsModel)(nil) + schema := dns_settings.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/dns_settings/resource_test.go b/internal/services/dns_settings/resource_test.go new file mode 100644 index 0000000000..719f040a85 --- /dev/null +++ b/internal/services/dns_settings/resource_test.go @@ -0,0 +1,84 @@ +package dns_settings_test + +import ( + "os" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDNSSettings_UpdateAccount(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_dns_settings." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDNSSettingsConfigAccount(rnd, accountID, false, false, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "account_id", accountID), + resource.TestCheckResourceAttr(name, "zone_defaults.flatten_all_cnames", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.foundation_dns", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.multi_provider", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.nameservers.type", "cloudflare.standard"), + resource.TestCheckResourceAttr(name, "zone_defaults.ns_ttl", "86400"), + resource.TestCheckResourceAttr(name, "zone_defaults.secondary_overrides", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.expire", "604800"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.min_ttl", "1800"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.mname", "kristina.ns.cloudflare.com"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.refresh", "10000"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.retry", "2400"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.rname", "admin.example.com"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.ttl", "3600"), + resource.TestCheckResourceAttr(name, "zone_defaults.zone_mode", "standard"), + ), + }, + }, + }) +} + +func TestAccDNSSettings_UpdateZone(t *testing.T) { + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_dns_settings." + rnd + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDNSSettingsConfigZone(rnd, zoneID, false, false, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "zone_id", zoneID), + resource.TestCheckResourceAttr(name, "zone_defaults.flatten_all_cnames", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.foundation_dns", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.multi_provider", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.nameservers.type", "cloudflare.standard"), + resource.TestCheckResourceAttr(name, "zone_defaults.ns_ttl", "86400"), + resource.TestCheckResourceAttr(name, "zone_defaults.secondary_overrides", "false"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.expire", "604800"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.min_ttl", "1800"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.mname", "kristina.ns.cloudflare.com"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.refresh", "10000"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.retry", "2400"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.rname", "admin.example.com"), + resource.TestCheckResourceAttr(name, "zone_defaults.soa.ttl", "3600"), + resource.TestCheckResourceAttr(name, "zone_defaults.zone_mode", "standard"), + ), + }, + }, + }) +} + +func testDNSSettingsConfigAccount(resourceID, ID string, flattenCnames, foundationDNS, multiProvider bool) string { + return acctest.LoadTestCase("account_setting.tf", resourceID, ID, flattenCnames, foundationDNS, multiProvider) +} + +func testDNSSettingsConfigZone(resourceID, ID string, flattenCnames, foundationDNS, multiProvider bool) string { + return acctest.LoadTestCase("zone_setting.tf", resourceID, ID, flattenCnames, foundationDNS, multiProvider) +} diff --git a/internal/services/dns_settings/schema.go b/internal/services/dns_settings/schema.go new file mode 100644 index 0000000000..8d2bc5df02 --- /dev/null +++ b/internal/services/dns_settings/schema.go @@ -0,0 +1,169 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*DNSSettingsResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "The Account ID to use for this endpoint. Mutually exclusive with the Zone ID.", + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "zone_id": schema.StringAttribute{ + Description: "The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.", + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "zone_defaults": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsModel](ctx), + Attributes: map[string]schema.Attribute{ + "flatten_all_cnames": schema.BoolAttribute{ + Description: "Whether to flatten all CNAME records in the zone. Note that, due to DNS limitations, a CNAME record at the zone apex will always be flattened.", + Optional: true, + }, + "foundation_dns": schema.BoolAttribute{ + Description: "Whether to enable Foundation DNS Advanced Nameservers on the zone.", + Optional: true, + }, + "internal_dns": schema.SingleNestedAttribute{ + Description: "Settings for this internal zone.", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsInternalDNSModel](ctx), + Attributes: map[string]schema.Attribute{ + "reference_zone_id": schema.StringAttribute{ + Description: "The ID of the zone to fallback to.", + Optional: true, + }, + }, + }, + "multi_provider": schema.BoolAttribute{ + Description: "Whether to enable multi-provider DNS, which causes Cloudflare to activate the zone even when non-Cloudflare NS records exist, and to respect NS records at the zone apex during outbound zone transfers.", + Optional: true, + }, + "nameservers": schema.SingleNestedAttribute{ + Description: "Settings determining the nameservers through which the zone should be available.", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsNameserversModel](ctx), + Attributes: map[string]schema.Attribute{ + "type": schema.StringAttribute{ + Description: "Nameserver type", + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "cloudflare.standard", + "cloudflare.standard.random", + "custom.account", + "custom.tenant", + ), + }, + }, + }, + }, + "ns_ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) of the zone's nameserver (NS) records.", + Optional: true, + Validators: []validator.Float64{ + float64validator.Between(30, 86400), + }, + }, + "secondary_overrides": schema.BoolAttribute{ + Description: "Allows a Secondary DNS zone to use (proxied) override records and CNAME flattening at the zone apex.", + Optional: true, + }, + "soa": schema.SingleNestedAttribute{ + Description: "Components of the zone's SOA record.", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[DNSSettingsZoneDefaultsSOAModel](ctx), + Attributes: map[string]schema.Attribute{ + "expire": schema.Float64Attribute{ + Description: "Time in seconds of being unable to query the primary server after which secondary servers should stop serving the zone.", + Required: true, + Validators: []validator.Float64{ + float64validator.Between(86400, 2419200), + }, + }, + "min_ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) for negative caching of records within the zone.", + Required: true, + Validators: []validator.Float64{ + float64validator.Between(60, 86400), + }, + }, + "mname": schema.StringAttribute{ + Description: "The primary nameserver, which may be used for outbound zone transfers.", + Required: true, + }, + "refresh": schema.Float64Attribute{ + Description: "Time in seconds after which secondary servers should re-check the SOA record to see if the zone has been updated.", + Required: true, + Validators: []validator.Float64{ + float64validator.Between(600, 86400), + }, + }, + "retry": schema.Float64Attribute{ + Description: "Time in seconds after which secondary servers should retry queries after the primary server was unresponsive.", + Required: true, + Validators: []validator.Float64{ + float64validator.Between(600, 86400), + }, + }, + "rname": schema.StringAttribute{ + Description: "The email address of the zone administrator, with the first label representing the local part of the email address.", + Required: true, + }, + "ttl": schema.Float64Attribute{ + Description: "The time to live (TTL) of the SOA record itself.", + Required: true, + Validators: []validator.Float64{ + float64validator.Between(300, 86400), + }, + }, + }, + }, + "zone_mode": schema.StringAttribute{ + Description: "Whether the zone mode is a regular or CDN/DNS only zone.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "standard", + "cdn_only", + "dns_only", + ), + }, + }, + }, + PlanModifiers: []planmodifier.Object{objectplanmodifier.RequiresReplace()}, + }, + }, + } +} + +func (r *DNSSettingsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *DNSSettingsResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/dns_settings/testdata/account_setting.tf b/internal/services/dns_settings/testdata/account_setting.tf new file mode 100644 index 0000000000..947f8f9f23 --- /dev/null +++ b/internal/services/dns_settings/testdata/account_setting.tf @@ -0,0 +1,24 @@ +resource "cloudflare_dns_settings" "%[1]s" { + account_id = "%[2]s" + + zone_defaults = { + flatten_all_cnames = "%[3]t" + foundation_dns = "%[4]t" + multi_provider = "%[5]t" + nameservers = { + type = "cloudflare.standard" + } + ns_ttl = 86400 + secondary_overrides = false + soa = { + expire = 604800 + min_ttl = 1800 + mname = "kristina.ns.cloudflare.com" + refresh = 10000 + retry = 2400 + rname = "admin.example.com" + ttl = 3600 + } + zone_mode = "standard" + } +} diff --git a/internal/services/dns_settings/testdata/zone_setting.tf b/internal/services/dns_settings/testdata/zone_setting.tf new file mode 100644 index 0000000000..b92f7cabbd --- /dev/null +++ b/internal/services/dns_settings/testdata/zone_setting.tf @@ -0,0 +1,24 @@ +resource "cloudflare_dns_settings" "%[1]s" { + zone_id = "%[2]s" + + zone_defaults = { + flatten_all_cnames = "%[3]t" + foundation_dns = "%[4]t" + multi_provider = "%[5]t" + nameservers = { + type = "cloudflare.standard" + } + ns_ttl = 86400 + secondary_overrides = false + soa = { + expire = 604800 + min_ttl = 1800 + mname = "kristina.ns.cloudflare.com" + refresh = 10000 + retry = 2400 + rname = "admin.example.com" + ttl = 3600 + } + zone_mode = "standard" + } +} diff --git a/internal/services/dns_settings_internal_view/data_source.go b/internal/services/dns_settings_internal_view/data_source.go new file mode 100644 index 0000000000..90b0477811 --- /dev/null +++ b/internal/services/dns_settings_internal_view/data_source.go @@ -0,0 +1,118 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type DNSSettingsInternalViewDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*DNSSettingsInternalViewDataSource)(nil) + +func NewDNSSettingsInternalViewDataSource() datasource.DataSource { + return &DNSSettingsInternalViewDataSource{} +} + +func (d *DNSSettingsInternalViewDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_settings_internal_view" +} + +func (d *DNSSettingsInternalViewDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *DNSSettingsInternalViewDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *DNSSettingsInternalViewDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if data.Filter != nil { + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := DNSSettingsInternalViewsResultListDataSourceEnvelope{} + page, err := d.client.DNS.Settings.Views.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + + if count := len(env.Result.Elements()); count != 1 { + resp.Diagnostics.AddError("failed to find exactly one result", fmt.Sprint(count)+" found") + return + } + ts, diags := env.Result.AsStructSliceT(ctx) + resp.Diagnostics.Append(diags...) + data.ViewID = ts[0].ID + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := DNSSettingsInternalViewResultDataSourceEnvelope{*data} + _, err := d.client.DNS.Settings.Views.Get( + ctx, + data.ViewID.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/dns_settings_internal_view/data_source_model.go b/internal/services/dns_settings_internal_view/data_source_model.go new file mode 100644 index 0000000000..be7fde9b28 --- /dev/null +++ b/internal/services/dns_settings_internal_view/data_source_model.go @@ -0,0 +1,93 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type DNSSettingsInternalViewResultDataSourceEnvelope struct { + Result DNSSettingsInternalViewDataSourceModel `json:"result,computed"` +} + +type DNSSettingsInternalViewDataSourceModel struct { + ID types.String `tfsdk:"id" json:"-,computed"` + ViewID types.String `tfsdk:"view_id" path:"view_id,optional"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + CreatedTime timetypes.RFC3339 `tfsdk:"created_time" json:"created_time,computed" format:"date-time"` + ModifiedTime timetypes.RFC3339 `tfsdk:"modified_time" json:"modified_time,computed" format:"date-time"` + Name types.String `tfsdk:"name" json:"name,computed"` + Zones customfield.List[types.String] `tfsdk:"zones" json:"zones,computed"` + Filter *DNSSettingsInternalViewFindOneByDataSourceModel `tfsdk:"filter"` +} + +func (m *DNSSettingsInternalViewDataSourceModel) toReadParams(_ context.Context) (params dns.SettingViewGetParams, diags diag.Diagnostics) { + params = dns.SettingViewGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +func (m *DNSSettingsInternalViewDataSourceModel) toListParams(_ context.Context) (params dns.SettingViewListParams, diags diag.Diagnostics) { + params = dns.SettingViewListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + if !m.Filter.Direction.IsNull() { + params.Direction = cloudflare.F(dns.SettingViewListParamsDirection(m.Filter.Direction.ValueString())) + } + if !m.Filter.Match.IsNull() { + params.Match = cloudflare.F(dns.SettingViewListParamsMatch(m.Filter.Match.ValueString())) + } + if m.Filter.Name != nil { + paramsName := dns.SettingViewListParamsName{} + if !m.Filter.Name.Contains.IsNull() { + paramsName.Contains = cloudflare.F(m.Filter.Name.Contains.ValueString()) + } + if !m.Filter.Name.Endswith.IsNull() { + paramsName.Endswith = cloudflare.F(m.Filter.Name.Endswith.ValueString()) + } + if !m.Filter.Name.Exact.IsNull() { + paramsName.Exact = cloudflare.F(m.Filter.Name.Exact.ValueString()) + } + if !m.Filter.Name.Startswith.IsNull() { + paramsName.Startswith = cloudflare.F(m.Filter.Name.Startswith.ValueString()) + } + params.Name = cloudflare.F(paramsName) + } + if !m.Filter.Order.IsNull() { + params.Order = cloudflare.F(dns.SettingViewListParamsOrder(m.Filter.Order.ValueString())) + } + if !m.Filter.ZoneID.IsNull() { + params.ZoneID = cloudflare.F(m.Filter.ZoneID.ValueString()) + } + if !m.Filter.ZoneName.IsNull() { + params.ZoneName = cloudflare.F(m.Filter.ZoneName.ValueString()) + } + + return +} + +type DNSSettingsInternalViewFindOneByDataSourceModel struct { + Direction types.String `tfsdk:"direction" query:"direction,computed_optional"` + Match types.String `tfsdk:"match" query:"match,computed_optional"` + Name *DNSSettingsInternalViewNameDataSourceModel `tfsdk:"name" query:"name,optional"` + Order types.String `tfsdk:"order" query:"order,optional"` + ZoneID types.String `tfsdk:"zone_id" query:"zone_id,optional"` + ZoneName types.String `tfsdk:"zone_name" query:"zone_name,optional"` +} + +type DNSSettingsInternalViewNameDataSourceModel struct { + Contains types.String `tfsdk:"contains" json:"contains,optional"` + Endswith types.String `tfsdk:"endswith" json:"endswith,optional"` + Exact types.String `tfsdk:"exact" json:"exact,optional"` + Startswith types.String `tfsdk:"startswith" json:"startswith,optional"` +} diff --git a/internal/services/dns_settings_internal_view/data_source_schema.go b/internal/services/dns_settings_internal_view/data_source_schema.go new file mode 100644 index 0000000000..57b760841d --- /dev/null +++ b/internal/services/dns_settings_internal_view/data_source_schema.go @@ -0,0 +1,129 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*DNSSettingsInternalViewDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, + "view_id": schema.StringAttribute{ + Description: "Identifier", + Optional: true, + }, + "account_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "created_time": schema.StringAttribute{ + Description: "When the view was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "modified_time": schema.StringAttribute{ + Description: "When the view was last modified.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "name": schema.StringAttribute{ + Description: "The name of the view.", + Computed: true, + }, + "zones": schema.ListAttribute{ + Description: "The list of zones linked to this view.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "filter": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "direction": schema.StringAttribute{ + Description: "Direction to order DNS views in.", + Computed: true, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("asc", "desc"), + }, + }, + "match": schema.StringAttribute{ + Description: "Whether to match all search requirements or at least one (any). If set to `all`, acts like a logical AND between filters. If set to `any`, acts like a logical OR instead.\n", + Computed: true, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("any", "all"), + }, + }, + "name": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "contains": schema.StringAttribute{ + Description: "Substring of the DNS view name.\n", + Optional: true, + }, + "endswith": schema.StringAttribute{ + Description: "Suffix of the DNS view name.\n", + Optional: true, + }, + "exact": schema.StringAttribute{ + Description: "Exact value of the DNS view name.\n", + Optional: true, + }, + "startswith": schema.StringAttribute{ + Description: "Prefix of the DNS view name.\n", + Optional: true, + }, + }, + }, + "order": schema.StringAttribute{ + Description: "Field to order DNS views by.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "name", + "created_on", + "modified_on", + ), + }, + }, + "zone_id": schema.StringAttribute{ + Description: "A zone ID that exists in the zones list for the view.\n", + Optional: true, + }, + "zone_name": schema.StringAttribute{ + Description: "A zone name that exists in the zones list for the view.\n", + Optional: true, + }, + }, + }, + }, + } +} + +func (d *DNSSettingsInternalViewDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *DNSSettingsInternalViewDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf(path.MatchRoot("view_id"), path.MatchRoot("filter")), + } +} diff --git a/internal/services/dns_settings_internal_view/data_source_schema_test.go b/internal/services/dns_settings_internal_view/data_source_schema_test.go new file mode 100644 index 0000000000..67be7eebcd --- /dev/null +++ b/internal/services/dns_settings_internal_view/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings_internal_view" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestDNSSettingsInternalViewDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*dns_settings_internal_view.DNSSettingsInternalViewDataSourceModel)(nil) + schema := dns_settings_internal_view.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/dns_settings_internal_view/list_data_source.go b/internal/services/dns_settings_internal_view/list_data_source.go new file mode 100644 index 0000000000..41f81b2041 --- /dev/null +++ b/internal/services/dns_settings_internal_view/list_data_source.go @@ -0,0 +1,100 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + "fmt" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type DNSSettingsInternalViewsDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*DNSSettingsInternalViewsDataSource)(nil) + +func NewDNSSettingsInternalViewsDataSource() datasource.DataSource { + return &DNSSettingsInternalViewsDataSource{} +} + +func (d *DNSSettingsInternalViewsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_settings_internal_views" +} + +func (d *DNSSettingsInternalViewsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *DNSSettingsInternalViewsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *DNSSettingsInternalViewsDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := DNSSettingsInternalViewsResultListDataSourceEnvelope{} + maxItems := int(data.MaxItems.ValueInt64()) + acc := []attr.Value{} + if maxItems <= 0 { + maxItems = 1000 + } + page, err := d.client.DNS.Settings.Views.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + for page != nil && len(page.Result) > 0 { + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + acc = append(acc, env.Result.Elements()...) + if len(acc) >= maxItems { + break + } + page, err = page.GetNextPage() + if err != nil { + resp.Diagnostics.AddError("failed to fetch next page", err.Error()) + return + } + } + + acc = acc[:min(len(acc), maxItems)] + result, diags := customfield.NewObjectListFromAttributes[DNSSettingsInternalViewsResultDataSourceModel](ctx, acc) + resp.Diagnostics.Append(diags...) + data.Result = result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/dns_settings_internal_view/list_data_source_model.go b/internal/services/dns_settings_internal_view/list_data_source_model.go new file mode 100644 index 0000000000..5b46a6c111 --- /dev/null +++ b/internal/services/dns_settings_internal_view/list_data_source_model.go @@ -0,0 +1,85 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type DNSSettingsInternalViewsResultListDataSourceEnvelope struct { + Result customfield.NestedObjectList[DNSSettingsInternalViewsResultDataSourceModel] `json:"result,computed"` +} + +type DNSSettingsInternalViewsDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Order types.String `tfsdk:"order" query:"order,optional"` + ZoneID types.String `tfsdk:"zone_id" query:"zone_id,optional"` + ZoneName types.String `tfsdk:"zone_name" query:"zone_name,optional"` + Name *DNSSettingsInternalViewsNameDataSourceModel `tfsdk:"name" query:"name,optional"` + Direction types.String `tfsdk:"direction" query:"direction,computed_optional"` + Match types.String `tfsdk:"match" query:"match,computed_optional"` + MaxItems types.Int64 `tfsdk:"max_items"` + Result customfield.NestedObjectList[DNSSettingsInternalViewsResultDataSourceModel] `tfsdk:"result"` +} + +func (m *DNSSettingsInternalViewsDataSourceModel) toListParams(_ context.Context) (params dns.SettingViewListParams, diags diag.Diagnostics) { + params = dns.SettingViewListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + if !m.Direction.IsNull() { + params.Direction = cloudflare.F(dns.SettingViewListParamsDirection(m.Direction.ValueString())) + } + if !m.Match.IsNull() { + params.Match = cloudflare.F(dns.SettingViewListParamsMatch(m.Match.ValueString())) + } + if m.Name != nil { + paramsName := dns.SettingViewListParamsName{} + if !m.Name.Contains.IsNull() { + paramsName.Contains = cloudflare.F(m.Name.Contains.ValueString()) + } + if !m.Name.Endswith.IsNull() { + paramsName.Endswith = cloudflare.F(m.Name.Endswith.ValueString()) + } + if !m.Name.Exact.IsNull() { + paramsName.Exact = cloudflare.F(m.Name.Exact.ValueString()) + } + if !m.Name.Startswith.IsNull() { + paramsName.Startswith = cloudflare.F(m.Name.Startswith.ValueString()) + } + params.Name = cloudflare.F(paramsName) + } + if !m.Order.IsNull() { + params.Order = cloudflare.F(dns.SettingViewListParamsOrder(m.Order.ValueString())) + } + if !m.ZoneID.IsNull() { + params.ZoneID = cloudflare.F(m.ZoneID.ValueString()) + } + if !m.ZoneName.IsNull() { + params.ZoneName = cloudflare.F(m.ZoneName.ValueString()) + } + + return +} + +type DNSSettingsInternalViewsNameDataSourceModel struct { + Contains types.String `tfsdk:"contains" json:"contains,optional"` + Endswith types.String `tfsdk:"endswith" json:"endswith,optional"` + Exact types.String `tfsdk:"exact" json:"exact,optional"` + Startswith types.String `tfsdk:"startswith" json:"startswith,optional"` +} + +type DNSSettingsInternalViewsResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + CreatedTime timetypes.RFC3339 `tfsdk:"created_time" json:"created_time,computed" format:"date-time"` + ModifiedTime timetypes.RFC3339 `tfsdk:"modified_time" json:"modified_time,computed" format:"date-time"` + Name types.String `tfsdk:"name" json:"name,computed"` + Zones customfield.List[types.String] `tfsdk:"zones" json:"zones,computed"` +} diff --git a/internal/services/dns_settings_internal_view/list_data_source_schema.go b/internal/services/dns_settings_internal_view/list_data_source_schema.go new file mode 100644 index 0000000000..2a53ada4eb --- /dev/null +++ b/internal/services/dns_settings_internal_view/list_data_source_schema.go @@ -0,0 +1,133 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*DNSSettingsInternalViewsDataSource)(nil) + +func ListDataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "order": schema.StringAttribute{ + Description: "Field to order DNS views by.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "name", + "created_on", + "modified_on", + ), + }, + }, + "zone_id": schema.StringAttribute{ + Description: "A zone ID that exists in the zones list for the view.\n", + Optional: true, + }, + "zone_name": schema.StringAttribute{ + Description: "A zone name that exists in the zones list for the view.\n", + Optional: true, + }, + "name": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "contains": schema.StringAttribute{ + Description: "Substring of the DNS view name.\n", + Optional: true, + }, + "endswith": schema.StringAttribute{ + Description: "Suffix of the DNS view name.\n", + Optional: true, + }, + "exact": schema.StringAttribute{ + Description: "Exact value of the DNS view name.\n", + Optional: true, + }, + "startswith": schema.StringAttribute{ + Description: "Prefix of the DNS view name.\n", + Optional: true, + }, + }, + }, + "direction": schema.StringAttribute{ + Description: "Direction to order DNS views in.", + Computed: true, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("asc", "desc"), + }, + }, + "match": schema.StringAttribute{ + Description: "Whether to match all search requirements or at least one (any). If set to `all`, acts like a logical AND between filters. If set to `any`, acts like a logical OR instead.\n", + Computed: true, + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("any", "all"), + }, + }, + "max_items": schema.Int64Attribute{ + Description: "Max items to fetch, default: 1000", + Optional: true, + Validators: []validator.Int64{ + int64validator.AtLeast(0), + }, + }, + "result": schema.ListNestedAttribute{ + Description: "The items returned by the data source", + Computed: true, + CustomType: customfield.NewNestedObjectListType[DNSSettingsInternalViewsResultDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, + "created_time": schema.StringAttribute{ + Description: "When the view was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "modified_time": schema.StringAttribute{ + Description: "When the view was last modified.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "name": schema.StringAttribute{ + Description: "The name of the view.", + Computed: true, + }, + "zones": schema.ListAttribute{ + Description: "The list of zones linked to this view.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, + }, + }, + }, + } +} + +func (d *DNSSettingsInternalViewsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = ListDataSourceSchema(ctx) +} + +func (d *DNSSettingsInternalViewsDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/dns_settings_internal_view/list_data_source_schema_test.go b/internal/services/dns_settings_internal_view/list_data_source_schema_test.go new file mode 100644 index 0000000000..4271232ba4 --- /dev/null +++ b/internal/services/dns_settings_internal_view/list_data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings_internal_view" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestDNSSettingsInternalViewsDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*dns_settings_internal_view.DNSSettingsInternalViewsDataSourceModel)(nil) + schema := dns_settings_internal_view.ListDataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/dns_settings_internal_view/migrations.go b/internal/services/dns_settings_internal_view/migrations.go new file mode 100644 index 0000000000..7e30753e09 --- /dev/null +++ b/internal/services/dns_settings_internal_view/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*DNSSettingsInternalViewResource)(nil) + +func (r *DNSSettingsInternalViewResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/dns_settings_internal_view/model.go b/internal/services/dns_settings_internal_view/model.go new file mode 100644 index 0000000000..96e727dc2d --- /dev/null +++ b/internal/services/dns_settings_internal_view/model.go @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type DNSSettingsInternalViewResultEnvelope struct { + Result DNSSettingsInternalViewModel `json:"result"` +} + +type DNSSettingsInternalViewModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Name types.String `tfsdk:"name" json:"name,required"` + Zones *[]types.String `tfsdk:"zones" json:"zones,required"` + CreatedTime timetypes.RFC3339 `tfsdk:"created_time" json:"created_time,computed" format:"date-time"` + ModifiedTime timetypes.RFC3339 `tfsdk:"modified_time" json:"modified_time,computed" format:"date-time"` +} + +func (m DNSSettingsInternalViewModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m DNSSettingsInternalViewModel) MarshalJSONForUpdate(state DNSSettingsInternalViewModel) (data []byte, err error) { + return apijson.MarshalForPatch(m, state) +} diff --git a/internal/services/dns_settings_internal_view/resource.go b/internal/services/dns_settings_internal_view/resource.go new file mode 100644 index 0000000000..ad0abf7530 --- /dev/null +++ b/internal/services/dns_settings_internal_view/resource.go @@ -0,0 +1,259 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*DNSSettingsInternalViewResource)(nil) +var _ resource.ResourceWithModifyPlan = (*DNSSettingsInternalViewResource)(nil) +var _ resource.ResourceWithImportState = (*DNSSettingsInternalViewResource)(nil) + +func NewResource() resource.Resource { + return &DNSSettingsInternalViewResource{} +} + +// DNSSettingsInternalViewResource defines the resource implementation. +type DNSSettingsInternalViewResource struct { + client *cloudflare.Client +} + +func (r *DNSSettingsInternalViewResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_settings_internal_view" +} + +func (r *DNSSettingsInternalViewResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *DNSSettingsInternalViewResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *DNSSettingsInternalViewModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := DNSSettingsInternalViewResultEnvelope{*data} + _, err = r.client.DNS.Settings.Views.New( + ctx, + dns.SettingViewNewParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsInternalViewResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *DNSSettingsInternalViewModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *DNSSettingsInternalViewModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := DNSSettingsInternalViewResultEnvelope{*data} + _, err = r.client.DNS.Settings.Views.Edit( + ctx, + data.ID.ValueString(), + dns.SettingViewEditParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsInternalViewResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *DNSSettingsInternalViewModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := DNSSettingsInternalViewResultEnvelope{*data} + _, err := r.client.DNS.Settings.Views.Get( + ctx, + data.ID.ValueString(), + dns.SettingViewGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsInternalViewResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *DNSSettingsInternalViewModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.DNS.Settings.Views.Delete( + ctx, + data.ID.ValueString(), + dns.SettingViewDeleteParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsInternalViewResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *DNSSettingsInternalViewModel = new(DNSSettingsInternalViewModel) + + path_account_id := "" + path_view_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_account_id, + &path_view_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountID = types.StringValue(path_account_id) + data.ID = types.StringValue(path_view_id) + + res := new(http.Response) + env := DNSSettingsInternalViewResultEnvelope{*data} + _, err := r.client.DNS.Settings.Views.Get( + ctx, + path_view_id, + dns.SettingViewGetParams{ + AccountID: cloudflare.F(path_account_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *DNSSettingsInternalViewResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/dns_settings_internal_view/resource_schema_test.go b/internal/services/dns_settings_internal_view/resource_schema_test.go new file mode 100644 index 0000000000..f36dce6721 --- /dev/null +++ b/internal/services/dns_settings_internal_view/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/dns_settings_internal_view" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestDNSSettingsInternalViewModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*dns_settings_internal_view.DNSSettingsInternalViewModel)(nil) + schema := dns_settings_internal_view.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/dns_settings_internal_view/resource_test.go b/internal/services/dns_settings_internal_view/resource_test.go new file mode 100644 index 0000000000..db739fb4c6 --- /dev/null +++ b/internal/services/dns_settings_internal_view/resource_test.go @@ -0,0 +1,110 @@ +package dns_settings_internal_view_test + +import ( + "context" + "errors" + "fmt" + "log" + "os" + "testing" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/dns" + "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" + "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func init() { + resource.AddTestSweepers("cloudflare_dns_settings_internal_view", &resource.Sweeper{ + Name: "cloudflare_dns_settings_internal_view", + F: testSweepCloudflareDNSSettingsInternalView, + }) +} + +func testSweepCloudflareDNSSettingsInternalView(r string) error { + ctx := context.Background() + client := acctest.SharedClient() + + // Clean up the account level views + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + if accountID == "" { + return errors.New("CLOUDFLARE_ACCOUNT_ID must be set") + } + + views, err := client.DNS.Settings.Views.List(context.Background(), dns.SettingViewListParams{AccountID: cloudflare.F(accountID)}) + if err != nil { + tflog.Error(ctx, fmt.Sprintf("Failed to fetch Cloudflare DNS internal views: %s", err)) + } + + if len(views.Result) == 0 { + log.Print("[DEBUG] No Cloudflare views to sweep") + return nil + } + + for _, view := range views.Result { + tflog.Info(ctx, fmt.Sprintf("Deleting Cloudflare View ID: %s", view.ID)) + //nolint:errcheck + client.DNS.Settings.Views.Delete(context.TODO(), view.ID, dns.SettingViewDeleteParams{AccountID: cloudflare.F(accountID)}) + } + + return nil +} + +func TestAccCloudflareDNSInternalView_Basic(t *testing.T) { + acctest.TestAccPreCheck_InternalZoneID(t) + + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_dns_settings_internal_view." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + internalZoneID := os.Getenv("CLOUDFLARE_INTERNAL_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDNSInternalViewConfig(rnd, accountID, rnd, internalZoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "zones.0", internalZoneID), + ), + }, + }, + }) +} + +func TestAccCloudflareDNSInternalView_Update(t *testing.T) { + acctest.TestAccPreCheck_InternalZoneID(t) + + rnd := utils.GenerateRandomResourceName() + name := "cloudflare_dns_settings_internal_view." + rnd + accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") + internalZoneID := os.Getenv("CLOUDFLARE_INTERNAL_ZONE_ID") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDNSInternalViewConfig(rnd, accountID, rnd, internalZoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd), + resource.TestCheckResourceAttr(name, "zones.0", internalZoneID), + ), + }, + { + Config: testDNSInternalViewConfig(rnd, accountID, rnd+"-update", internalZoneID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "name", rnd+"-update"), + resource.TestCheckResourceAttr(name, "zones.0", internalZoneID), + ), + }, + }, + }) +} + +func testDNSInternalViewConfig(resourceID, accountID, name, zone string) string { + return acctest.LoadTestCase("view.tf", resourceID, accountID, name, zone) +} diff --git a/internal/services/dns_settings_internal_view/schema.go b/internal/services/dns_settings_internal_view/schema.go new file mode 100644 index 0000000000..d2c0d0fe9c --- /dev/null +++ b/internal/services/dns_settings_internal_view/schema.go @@ -0,0 +1,60 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package dns_settings_internal_view + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ resource.ResourceWithConfigValidators = (*DNSSettingsInternalViewResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "account_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "name": schema.StringAttribute{ + Description: "The name of the view.", + Required: true, + }, + "zones": schema.ListAttribute{ + Description: "The list of zones linked to this view.", + Required: true, + ElementType: types.StringType, + }, + "created_time": schema.StringAttribute{ + Description: "When the view was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "modified_time": schema.StringAttribute{ + Description: "When the view was last modified.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + } +} + +func (r *DNSSettingsInternalViewResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *DNSSettingsInternalViewResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/dns_settings_internal_view/testdata/view.tf b/internal/services/dns_settings_internal_view/testdata/view.tf new file mode 100644 index 0000000000..48b13383c5 --- /dev/null +++ b/internal/services/dns_settings_internal_view/testdata/view.tf @@ -0,0 +1,5 @@ +resource "cloudflare_dns_settings_internal_view" "%[1]s" { + account_id = "%[2]s" + name = "%[3]s" + zones = ["%[4]s"] +} diff --git a/internal/services/dns_zone_transfers_acl/data_source_model.go b/internal/services/dns_zone_transfers_acl/data_source_model.go index ddc33ae06e..a970d88557 100644 --- a/internal/services/dns_zone_transfers_acl/data_source_model.go +++ b/internal/services/dns_zone_transfers_acl/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/dns" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type DNSZoneTransfersACLResultDataSourceEnvelope struct { Result DNSZoneTransfersACLDataSourceModel `json:"result,computed"` } -type DNSZoneTransfersACLResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[DNSZoneTransfersACLDataSourceModel] `json:"result,computed"` -} - type DNSZoneTransfersACLDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ACLID types.String `tfsdk:"acl_id" path:"acl_id,optional"` diff --git a/internal/services/dns_zone_transfers_incoming/resource_test.go b/internal/services/dns_zone_transfers_incoming/resource_test.go index b6b06dc6e3..e0e7d69716 100644 --- a/internal/services/dns_zone_transfers_incoming/resource_test.go +++ b/internal/services/dns_zone_transfers_incoming/resource_test.go @@ -19,11 +19,11 @@ import ( func init() { resource.AddTestSweepers("cloudflare_dns_zone_transfers_incoming", &resource.Sweeper{ Name: "cloudflare_dns_zone_transfers_incoming", - F: testSweepCloudflareSecondaryDNSIncoming, + F: testSweepCloudflareDNSZoneTransfersIncoming, }) } -func testSweepCloudflareSecondaryDNSIncoming(r string) error { +func testSweepCloudflareDNSZoneTransfersIncoming(r string) error { ctx := context.Background() client := acctest.SharedClient() @@ -51,79 +51,53 @@ func testSweepCloudflareSecondaryDNSIncoming(r string) error { return nil } -func TestAccCloudflareSecondaryDNSIncoming_Basic(t *testing.T) { +func TestAccCloudflareDNSZoneTransfersIncoming_Basic(t *testing.T) { rnd := utils.GenerateRandomResourceName() zoneName := os.Getenv("CLOUDFLARE_DOMAIN") name := "cloudflare_dns_zone_transfers_incoming." + rnd zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") - client := acctest.SharedClient() - - peer, err := client.DNS.ZoneTransfers.Peers.New(context.Background(), dns.ZoneTransferPeerNewParams{AccountID: cloudflare.F(accountID), Name: cloudflare.F("terraform-peer")}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to bootstrap Cloudflare DNS peer: %s", err)) - } - resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testSecondaryDNSIncomingConfig(rnd, zoneName, zoneID, 300, peer.ID), + Config: testDNSZoneTransfersIncomingConfig(rnd, zoneName, zoneID, 300, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", zoneName), resource.TestCheckResourceAttr(name, "auto_refresh_seconds", "300"), - resource.TestCheckResourceAttr(name, "peers.0", peer.ID), ), }, }, }) - // Delete the original peer after we are done - _, err = client.DNS.ZoneTransfers.Peers.Delete(context.Background(), peer.ID, dns.ZoneTransferPeerDeleteParams{AccountID: cloudflare.F(accountID)}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to cleanup Cloudflare DNS peer in incoming test: %s", err)) - } } -func TestAccCloudflareSecondaryDNSIncoming_Update(t *testing.T) { +func TestAccCloudflareDNSZoneTransfersIncoming_Update(t *testing.T) { rnd := utils.GenerateRandomResourceName() zoneName := os.Getenv("CLOUDFLARE_DOMAIN") name := "cloudflare_dns_zone_transfers_incoming." + rnd zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") - client := acctest.SharedClient() - - peer, err := client.DNS.ZoneTransfers.Peers.New(context.Background(), dns.ZoneTransferPeerNewParams{AccountID: cloudflare.F(accountID), Name: cloudflare.F("terraform-peer")}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to bootstrap Cloudflare DNS peer: %s", err)) - } - resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testSecondaryDNSIncomingConfig(rnd, zoneName, zoneID, 300, peer.ID), + Config: testDNSZoneTransfersIncomingConfig(rnd, zoneName, zoneID, 300, accountID), }, { - Config: testSecondaryDNSIncomingConfig(rnd, zoneName, zoneID, 500, peer.ID), + Config: testDNSZoneTransfersIncomingConfig(rnd, zoneName, zoneID, 500, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", zoneName), resource.TestCheckResourceAttr(name, "auto_refresh_seconds", "500"), - resource.TestCheckResourceAttr(name, "peers.0", peer.ID), ), }, }, }) - // Delete the original peer after we are done - _, err = client.DNS.ZoneTransfers.Peers.Delete(context.Background(), peer.ID, dns.ZoneTransferPeerDeleteParams{AccountID: cloudflare.F(accountID)}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to cleanup Cloudflare DNS peer in incoming test: %s", err)) - } } -func testSecondaryDNSIncomingConfig(resourceID, zoneName, zoneID string, autoRefreshSeconds int, peers string) string { - return acctest.LoadTestCase("incoming.tf", resourceID, zoneID, autoRefreshSeconds, zoneName, peers) +func testDNSZoneTransfersIncomingConfig(resourceID, zoneName, zoneID string, autoRefreshSeconds int, accountID string) string { + return acctest.LoadTestCase("incoming.tf", resourceID, zoneID, autoRefreshSeconds, zoneName, accountID) } diff --git a/internal/services/dns_zone_transfers_incoming/testdata/incoming.tf b/internal/services/dns_zone_transfers_incoming/testdata/incoming.tf index 378f9e59f4..d7dd8b18a9 100644 --- a/internal/services/dns_zone_transfers_incoming/testdata/incoming.tf +++ b/internal/services/dns_zone_transfers_incoming/testdata/incoming.tf @@ -1,6 +1,11 @@ -resource "cloudflare_secondary_dns_incoming" "%[1]s" { +resource "cloudflare_dns_zone_transfers_peer" "%[1]s" { + account_id = "%[5]s" + name = "%[1]s" +} + +resource "cloudflare_dns_zone_transfers_incoming" "%[1]s" { zone_id = "%[2]s" auto_refresh_seconds = "%[3]d" name = "%[4]s" - peers = ["%[5]s"] + peers = [cloudflare_dns_zone_transfers_peer.%[1]s.id] } diff --git a/internal/services/dns_zone_transfers_outgoing/resource_test.go b/internal/services/dns_zone_transfers_outgoing/resource_test.go index 9c4d601f23..46dd99733b 100644 --- a/internal/services/dns_zone_transfers_outgoing/resource_test.go +++ b/internal/services/dns_zone_transfers_outgoing/resource_test.go @@ -58,31 +58,18 @@ func TestAccCloudflareSecondaryDNSOutgoing_Basic(t *testing.T) { zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") - client := acctest.SharedClient() - - peer, err := client.DNS.ZoneTransfers.Peers.New(context.Background(), dns.ZoneTransferPeerNewParams{AccountID: cloudflare.F(accountID), Name: cloudflare.F("terraform-peer")}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to bootstrap Cloudflare DNS peer: %s", err)) - } - resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, peer.ID), + Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", zoneName), - resource.TestCheckResourceAttr(name, "peers.0", peer.ID), ), }, }, }) - // Delete the original peer after we are done - _, err = client.DNS.ZoneTransfers.Peers.Delete(context.Background(), peer.ID, dns.ZoneTransferPeerDeleteParams{AccountID: cloudflare.F(accountID)}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to cleanup Cloudflare DNS peer in outgoing test: %s", err)) - } } func TestAccCloudflareSecondaryDNSOutgoing_Update(t *testing.T) { @@ -92,44 +79,23 @@ func TestAccCloudflareSecondaryDNSOutgoing_Update(t *testing.T) { zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") accountID := os.Getenv("CLOUDFLARE_ACCOUNT_ID") - client := acctest.SharedClient() - - peer1, err := client.DNS.ZoneTransfers.Peers.New(context.Background(), dns.ZoneTransferPeerNewParams{AccountID: cloudflare.F(accountID), Name: cloudflare.F("terraform-peer")}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to bootstrap Cloudflare DNS peer: %s", err)) - } - - peer2, err := client.DNS.ZoneTransfers.Peers.New(context.Background(), dns.ZoneTransferPeerNewParams{AccountID: cloudflare.F(accountID), Name: cloudflare.F("terraform-peer")}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to bootstrap Cloudflare DNS peer: %s", err)) - } - resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, peer1.ID), + Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, accountID), }, { - Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, peer2.ID), + Config: testSecondaryDNSOutgoingConfig(rnd, zoneName, zoneID, accountID), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(name, "name", zoneName), - resource.TestCheckResourceAttr(name, "peers.0", peer2.ID), ), }, }, }) - // Delete the original peers after we are done - for _, id := range []string{peer1.ID, peer2.ID} { - _, err = client.DNS.ZoneTransfers.Peers.Delete(context.Background(), id, dns.ZoneTransferPeerDeleteParams{AccountID: cloudflare.F(accountID)}) - if err != nil { - tflog.Error(context.Background(), fmt.Sprintf("Failed to cleanup Cloudflare DNS peer in outgoing test: %s", err)) - } - } - } -func testSecondaryDNSOutgoingConfig(resourceID, zoneName, zoneID string, peers string) string { - return acctest.LoadTestCase("outgoing.tf", resourceID, zoneID, zoneName, peers) +func testSecondaryDNSOutgoingConfig(resourceID, zoneName, zoneID string, accountID string) string { + return acctest.LoadTestCase("outgoing.tf", resourceID, zoneID, zoneName, accountID) } diff --git a/internal/services/dns_zone_transfers_outgoing/testdata/outgoing.tf b/internal/services/dns_zone_transfers_outgoing/testdata/outgoing.tf index f9a28036f2..688bc2becd 100644 --- a/internal/services/dns_zone_transfers_outgoing/testdata/outgoing.tf +++ b/internal/services/dns_zone_transfers_outgoing/testdata/outgoing.tf @@ -1,5 +1,10 @@ +resource "cloudflare_dns_zone_transfers_peer" "%[1]s" { + account_id = "%[4]s" + name = "%[1]s" +} + resource "cloudflare_dns_zone_transfers_outgoing" "%[1]s" { zone_id = "%[2]s" name = "%[3]s" - peers = ["%[4]s"] + peers = [cloudflare_dns_zone_transfers_peer.%[1]s.id] } diff --git a/internal/services/dns_zone_transfers_peer/data_source_model.go b/internal/services/dns_zone_transfers_peer/data_source_model.go index 18b12318f9..11aac55d94 100644 --- a/internal/services/dns_zone_transfers_peer/data_source_model.go +++ b/internal/services/dns_zone_transfers_peer/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/dns" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type DNSZoneTransfersPeerResultDataSourceEnvelope struct { Result DNSZoneTransfersPeerDataSourceModel `json:"result,computed"` } -type DNSZoneTransfersPeerResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[DNSZoneTransfersPeerDataSourceModel] `json:"result,computed"` -} - type DNSZoneTransfersPeerDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PeerID types.String `tfsdk:"peer_id" path:"peer_id,optional"` diff --git a/internal/services/dns_zone_transfers_tsig/data_source_model.go b/internal/services/dns_zone_transfers_tsig/data_source_model.go index d9c6aeb577..3dfa5ff282 100644 --- a/internal/services/dns_zone_transfers_tsig/data_source_model.go +++ b/internal/services/dns_zone_transfers_tsig/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/dns" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type DNSZoneTransfersTSIGResultDataSourceEnvelope struct { Result DNSZoneTransfersTSIGDataSourceModel `json:"result,computed"` } -type DNSZoneTransfersTSIGResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[DNSZoneTransfersTSIGDataSourceModel] `json:"result,computed"` -} - type DNSZoneTransfersTSIGDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TSIGID types.String `tfsdk:"tsig_id" path:"tsig_id,optional"` diff --git a/internal/services/email_routing_address/data_source.go b/internal/services/email_routing_address/data_source.go index f30e9f3294..e5f48a5102 100644 --- a/internal/services/email_routing_address/data_source.go +++ b/internal/services/email_routing_address/data_source.go @@ -64,7 +64,7 @@ func (d *EmailRoutingAddressDataSource) Read(ctx context.Context, req datasource return } - env := EmailRoutingAddressResultListDataSourceEnvelope{} + env := EmailRoutingAddressesResultListDataSourceEnvelope{} page, err := d.client.EmailRouting.Addresses.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *EmailRoutingAddressDataSource) Read(ctx context.Context, req datasource } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.DestinationAddressIdentifier = ts[0].DestinationAddressIdentifier + data.DestinationAddressIdentifier = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/email_routing_address/data_source_model.go b/internal/services/email_routing_address/data_source_model.go index 63bf657232..90dd43a5ac 100644 --- a/internal/services/email_routing_address/data_source_model.go +++ b/internal/services/email_routing_address/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/email_routing" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type EmailRoutingAddressResultDataSourceEnvelope struct { Result EmailRoutingAddressDataSourceModel `json:"result,computed"` } -type EmailRoutingAddressResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[EmailRoutingAddressDataSourceModel] `json:"result,computed"` -} - type EmailRoutingAddressDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DestinationAddressIdentifier types.String `tfsdk:"destination_address_identifier" path:"destination_address_identifier,optional"` diff --git a/internal/services/email_routing_rule/data_source.go b/internal/services/email_routing_rule/data_source.go index 8963b1ba08..fcfca0914c 100644 --- a/internal/services/email_routing_rule/data_source.go +++ b/internal/services/email_routing_rule/data_source.go @@ -64,7 +64,7 @@ func (d *EmailRoutingRuleDataSource) Read(ctx context.Context, req datasource.Re return } - env := EmailRoutingRuleResultListDataSourceEnvelope{} + env := EmailRoutingRulesResultListDataSourceEnvelope{} page, err := d.client.EmailRouting.Rules.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *EmailRoutingRuleDataSource) Read(ctx context.Context, req datasource.Re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.RuleIdentifier = ts[0].RuleIdentifier + data.RuleIdentifier = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/email_routing_rule/data_source_model.go b/internal/services/email_routing_rule/data_source_model.go index 77c3ad1cbf..de0fdf2fc5 100644 --- a/internal/services/email_routing_rule/data_source_model.go +++ b/internal/services/email_routing_rule/data_source_model.go @@ -16,10 +16,6 @@ type EmailRoutingRuleResultDataSourceEnvelope struct { Result EmailRoutingRuleDataSourceModel `json:"result,computed"` } -type EmailRoutingRuleResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[EmailRoutingRuleDataSourceModel] `json:"result,computed"` -} - type EmailRoutingRuleDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RuleIdentifier types.String `tfsdk:"rule_identifier" path:"rule_identifier,optional"` diff --git a/internal/services/email_security_block_sender/data_source.go b/internal/services/email_security_block_sender/data_source.go index 8f828a0fdb..1805c3d713 100644 --- a/internal/services/email_security_block_sender/data_source.go +++ b/internal/services/email_security_block_sender/data_source.go @@ -64,7 +64,7 @@ func (d *EmailSecurityBlockSenderDataSource) Read(ctx context.Context, req datas return } - env := EmailSecurityBlockSenderResultListDataSourceEnvelope{} + env := EmailSecurityBlockSendersResultListDataSourceEnvelope{} page, err := d.client.EmailSecurity.Settings.BlockSenders.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *EmailSecurityBlockSenderDataSource) Read(ctx context.Context, req datas } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.PatternID = ts[0].PatternID + data.PatternID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/email_security_block_sender/data_source_model.go b/internal/services/email_security_block_sender/data_source_model.go index cbe4216ea2..d286533b72 100644 --- a/internal/services/email_security_block_sender/data_source_model.go +++ b/internal/services/email_security_block_sender/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/email_security" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type EmailSecurityBlockSenderResultDataSourceEnvelope struct { Result EmailSecurityBlockSenderDataSourceModel `json:"result,computed"` } -type EmailSecurityBlockSenderResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[EmailSecurityBlockSenderDataSourceModel] `json:"result,computed"` -} - type EmailSecurityBlockSenderDataSourceModel struct { ID types.Int64 `tfsdk:"id" json:"-,computed"` PatternID types.Int64 `tfsdk:"pattern_id" path:"pattern_id,optional"` diff --git a/internal/services/email_security_impersonation_registry/data_source.go b/internal/services/email_security_impersonation_registry/data_source.go index 604fe69f4f..4f041d1b78 100644 --- a/internal/services/email_security_impersonation_registry/data_source.go +++ b/internal/services/email_security_impersonation_registry/data_source.go @@ -64,7 +64,7 @@ func (d *EmailSecurityImpersonationRegistryDataSource) Read(ctx context.Context, return } - env := EmailSecurityImpersonationRegistryResultListDataSourceEnvelope{} + env := EmailSecurityImpersonationRegistriesResultListDataSourceEnvelope{} page, err := d.client.EmailSecurity.Settings.ImpersonationRegistry.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *EmailSecurityImpersonationRegistryDataSource) Read(ctx context.Context, } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.DisplayNameID = ts[0].DisplayNameID + data.DisplayNameID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/email_security_impersonation_registry/data_source_model.go b/internal/services/email_security_impersonation_registry/data_source_model.go index 678f3e3754..eecec59e78 100644 --- a/internal/services/email_security_impersonation_registry/data_source_model.go +++ b/internal/services/email_security_impersonation_registry/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/email_security" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type EmailSecurityImpersonationRegistryResultDataSourceEnvelope struct { Result EmailSecurityImpersonationRegistryDataSourceModel `json:"result,computed"` } -type EmailSecurityImpersonationRegistryResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[EmailSecurityImpersonationRegistryDataSourceModel] `json:"result,computed"` -} - type EmailSecurityImpersonationRegistryDataSourceModel struct { ID types.Int64 `tfsdk:"id" json:"-,computed"` DisplayNameID types.Int64 `tfsdk:"display_name_id" path:"display_name_id,optional"` diff --git a/internal/services/email_security_trusted_domains/data_source.go b/internal/services/email_security_trusted_domains/data_source.go index 58735355cb..1077975dfa 100644 --- a/internal/services/email_security_trusted_domains/data_source.go +++ b/internal/services/email_security_trusted_domains/data_source.go @@ -64,7 +64,7 @@ func (d *EmailSecurityTrustedDomainsDataSource) Read(ctx context.Context, req da return } - env := EmailSecurityTrustedDomainsResultListDataSourceEnvelope{} + env := EmailSecurityTrustedDomainsListResultListDataSourceEnvelope{} page, err := d.client.EmailSecurity.Settings.TrustedDomains.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *EmailSecurityTrustedDomainsDataSource) Read(ctx context.Context, req da } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.TrustedDomainID = ts[0].TrustedDomainID + data.TrustedDomainID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/email_security_trusted_domains/data_source_model.go b/internal/services/email_security_trusted_domains/data_source_model.go index 89348ea559..306ffa93cc 100644 --- a/internal/services/email_security_trusted_domains/data_source_model.go +++ b/internal/services/email_security_trusted_domains/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/email_security" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type EmailSecurityTrustedDomainsResultDataSourceEnvelope struct { Result EmailSecurityTrustedDomainsDataSourceModel `json:"result,computed"` } -type EmailSecurityTrustedDomainsResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[EmailSecurityTrustedDomainsDataSourceModel] `json:"result,computed"` -} - type EmailSecurityTrustedDomainsDataSourceModel struct { ID types.Int64 `tfsdk:"id" json:"-,computed"` TrustedDomainID types.Int64 `tfsdk:"trusted_domain_id" path:"trusted_domain_id,optional"` diff --git a/internal/services/filter/data_source.go b/internal/services/filter/data_source.go index 12fafb2191..46ea7488a3 100644 --- a/internal/services/filter/data_source.go +++ b/internal/services/filter/data_source.go @@ -57,6 +57,36 @@ func (d *FilterDataSource) Read(ctx context.Context, req datasource.ReadRequest, return } + if data.Filter != nil { + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := FiltersResultListDataSourceEnvelope{} + page, err := d.client.Filters.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + + if count := len(env.Result.Elements()); count != 1 { + resp.Diagnostics.AddError("failed to find exactly one result", fmt.Sprint(count)+" found") + return + } + ts, diags := env.Result.AsStructSliceT(ctx) + resp.Diagnostics.Append(diags...) + data.FilterID = ts[0].ID + } + params, diags := data.toReadParams(ctx) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/internal/services/filter/data_source_model.go b/internal/services/filter/data_source_model.go index 3b3cc8c7be..6c61cc5789 100644 --- a/internal/services/filter/data_source_model.go +++ b/internal/services/filter/data_source_model.go @@ -16,13 +16,14 @@ type FilterResultDataSourceEnvelope struct { } type FilterDataSourceModel struct { - FilterID types.String `tfsdk:"filter_id" path:"filter_id,required"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Description types.String `tfsdk:"description" json:"description,computed"` - Expression types.String `tfsdk:"expression" json:"expression,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` - Paused types.Bool `tfsdk:"paused" json:"paused,computed"` - Ref types.String `tfsdk:"ref" json:"ref,computed"` + ID types.String `tfsdk:"id" json:"-,computed"` + FilterID types.String `tfsdk:"filter_id" path:"filter_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Expression types.String `tfsdk:"expression" json:"expression,computed"` + Paused types.Bool `tfsdk:"paused" json:"paused,computed"` + Ref types.String `tfsdk:"ref" json:"ref,computed"` + Filter *FilterFindOneByDataSourceModel `tfsdk:"filter"` } func (m *FilterDataSourceModel) toReadParams(_ context.Context) (params filters.FilterGetParams, diags diag.Diagnostics) { @@ -32,3 +33,35 @@ func (m *FilterDataSourceModel) toReadParams(_ context.Context) (params filters. return } + +func (m *FilterDataSourceModel) toListParams(_ context.Context) (params filters.FilterListParams, diags diag.Diagnostics) { + params = filters.FilterListParams{ + ZoneID: cloudflare.F(m.ZoneID.ValueString()), + } + + if !m.Filter.ID.IsNull() { + params.ID = cloudflare.F(m.Filter.ID.ValueString()) + } + if !m.Filter.Description.IsNull() { + params.Description = cloudflare.F(m.Filter.Description.ValueString()) + } + if !m.Filter.Expression.IsNull() { + params.Expression = cloudflare.F(m.Filter.Expression.ValueString()) + } + if !m.Filter.Paused.IsNull() { + params.Paused = cloudflare.F(m.Filter.Paused.ValueBool()) + } + if !m.Filter.Ref.IsNull() { + params.Ref = cloudflare.F(m.Filter.Ref.ValueString()) + } + + return +} + +type FilterFindOneByDataSourceModel struct { + ID types.String `tfsdk:"id" query:"id,optional"` + Description types.String `tfsdk:"description" query:"description,optional"` + Expression types.String `tfsdk:"expression" query:"expression,optional"` + Paused types.Bool `tfsdk:"paused" query:"paused,optional"` + Ref types.String `tfsdk:"ref" query:"ref,optional"` +} diff --git a/internal/services/filter/data_source_schema.go b/internal/services/filter/data_source_schema.go index f46e0fab58..ef6c27b5c3 100644 --- a/internal/services/filter/data_source_schema.go +++ b/internal/services/filter/data_source_schema.go @@ -5,8 +5,10 @@ package filter import ( "context" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" ) var _ datasource.DataSourceWithConfigValidators = (*FilterDataSource)(nil) @@ -14,9 +16,13 @@ var _ datasource.DataSourceWithConfigValidators = (*FilterDataSource)(nil) func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the filter.", + Computed: true, + }, "filter_id": schema.StringAttribute{ Description: "The unique identifier of the filter.", - Required: true, + Optional: true, }, "zone_id": schema.StringAttribute{ Description: "Identifier", @@ -30,10 +36,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "The filter expression. For more information, refer to [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/).", Computed: true, }, - "id": schema.StringAttribute{ - Description: "The unique identifier of the filter.", - Computed: true, - }, "paused": schema.BoolAttribute{ Description: "When true, indicates that the filter is currently paused.", Computed: true, @@ -42,6 +44,31 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "A short reference tag. Allows you to select related filters.", Computed: true, }, + "filter": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the filter.", + Optional: true, + }, + "description": schema.StringAttribute{ + Description: "A case-insensitive string to find in the description.", + Optional: true, + }, + "expression": schema.StringAttribute{ + Description: "A case-insensitive string to find in the expression.", + Optional: true, + }, + "paused": schema.BoolAttribute{ + Description: "When true, indicates that the filter is currently paused.", + Optional: true, + }, + "ref": schema.StringAttribute{ + Description: "The filter ref (a short reference tag) to search for. Must be an exact match.", + Optional: true, + }, + }, + }, }, } } @@ -51,5 +78,7 @@ func (d *FilterDataSource) Schema(ctx context.Context, req datasource.SchemaRequ } func (d *FilterDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{} + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf(path.MatchRoot("filter_id"), path.MatchRoot("filter")), + } } diff --git a/internal/services/filter/model.go b/internal/services/filter/model.go index bc507d1ca6..023bcd8ba5 100644 --- a/internal/services/filter/model.go +++ b/internal/services/filter/model.go @@ -12,11 +12,10 @@ type FilterResultEnvelope struct { } type FilterModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - FilterID types.String `tfsdk:"filter_id" path:"filter_id,optional"` Expression types.String `tfsdk:"expression" json:"expression,required"` Description types.String `tfsdk:"description" json:"description,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` Paused types.Bool `tfsdk:"paused" json:"paused,computed"` Ref types.String `tfsdk:"ref" json:"ref,computed"` } diff --git a/internal/services/filter/resource.go b/internal/services/filter/resource.go index 4aee6fcb47..e098c6a6fa 100644 --- a/internal/services/filter/resource.go +++ b/internal/services/filter/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/filters" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*FilterResource)(nil) var _ resource.ResourceWithModifyPlan = (*FilterResource)(nil) +var _ resource.ResourceWithImportState = (*FilterResource)(nil) func NewResource() resource.Resource { return &FilterResource{} @@ -118,7 +121,7 @@ func (r *FilterResource) Update(ctx context.Context, req resource.UpdateRequest, env := FilterResultEnvelope{*data} _, err = r.client.Filters.Update( ctx, - data.FilterID.ValueString(), + data.ID.ValueString(), filters.FilterUpdateParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -154,7 +157,7 @@ func (r *FilterResource) Read(ctx context.Context, req resource.ReadRequest, res env := FilterResultEnvelope{*data} _, err := r.client.Filters.Get( ctx, - data.FilterID.ValueString(), + data.ID.ValueString(), filters.FilterGetParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -192,7 +195,7 @@ func (r *FilterResource) Delete(ctx context.Context, req resource.DeleteRequest, _, err := r.client.Filters.Delete( ctx, - data.FilterID.ValueString(), + data.ID.ValueString(), filters.FilterDeleteParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -206,6 +209,51 @@ func (r *FilterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *FilterResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *FilterModel = new(FilterModel) + + path_zone_id := "" + path_filter_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_zone_id, + &path_filter_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.ZoneID = types.StringValue(path_zone_id) + data.ID = types.StringValue(path_filter_id) + + res := new(http.Response) + env := FilterResultEnvelope{*data} + _, err := r.client.Filters.Get( + ctx, + path_filter_id, + filters.FilterGetParams{ + ZoneID: cloudflare.F(path_zone_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *FilterResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/filter/schema.go b/internal/services/filter/schema.go index 38c855ca56..dea10f7fc0 100644 --- a/internal/services/filter/schema.go +++ b/internal/services/filter/schema.go @@ -16,16 +16,16 @@ var _ resource.ResourceWithConfigValidators = (*FilterResource)(nil) func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the filter.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, "zone_id": schema.StringAttribute{ Description: "Identifier", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "filter_id": schema.StringAttribute{ - Description: "The unique identifier of the filter.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "expression": schema.StringAttribute{ Description: "The filter expression. For more information, refer to [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/).", Required: true, @@ -35,10 +35,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "An informative summary of the filter.", Computed: true, }, - "id": schema.StringAttribute{ - Description: "The unique identifier of the filter.", - Computed: true, - }, "paused": schema.BoolAttribute{ Description: "When true, indicates that the filter is currently paused.", Computed: true, diff --git a/internal/services/firewall_rule/data_source_model.go b/internal/services/firewall_rule/data_source_model.go index 0d1fce25aa..8c2c626446 100644 --- a/internal/services/firewall_rule/data_source_model.go +++ b/internal/services/firewall_rule/data_source_model.go @@ -17,16 +17,15 @@ type FirewallRuleResultDataSourceEnvelope struct { } type FirewallRuleDataSourceModel struct { - RuleID types.String `tfsdk:"rule_id" path:"rule_id,required"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - ID types.String `tfsdk:"id" query:"id,computed_optional"` - Action types.String `tfsdk:"action" json:"action,computed"` - Description types.String `tfsdk:"description" json:"description,computed"` - Paused types.Bool `tfsdk:"paused" json:"paused,computed"` - Priority types.Float64 `tfsdk:"priority" json:"priority,computed"` - Ref types.String `tfsdk:"ref" json:"ref,computed"` - Products customfield.List[types.String] `tfsdk:"products" json:"products,computed"` - Filter customfield.NestedObject[FirewallRuleFilterDataSourceModel] `tfsdk:"filter" json:"filter,computed"` + ID types.String `tfsdk:"id" query:"id,optional" json:"-,computed"` + RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Action types.String `tfsdk:"action" json:"action,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Paused types.Bool `tfsdk:"paused" json:"paused,computed"` + Priority types.Float64 `tfsdk:"priority" json:"priority,computed"` + Ref types.String `tfsdk:"ref" json:"ref,computed"` + Products customfield.List[types.String] `tfsdk:"products" json:"products,computed"` } func (m *FirewallRuleDataSourceModel) toReadParams(_ context.Context) (params firewall.RuleGetParams, diags diag.Diagnostics) { @@ -37,11 +36,10 @@ func (m *FirewallRuleDataSourceModel) toReadParams(_ context.Context) (params fi return } -type FirewallRuleFilterDataSourceModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` - Description types.String `tfsdk:"description" json:"description,computed"` - Expression types.String `tfsdk:"expression" json:"expression,computed"` - Paused types.Bool `tfsdk:"paused" json:"paused,computed"` - Ref types.String `tfsdk:"ref" json:"ref,computed"` - Deleted types.Bool `tfsdk:"deleted" json:"deleted,computed"` +func (m *FirewallRuleDataSourceModel) toListParams(_ context.Context) (params firewall.RuleListParams, diags diag.Diagnostics) { + params = firewall.RuleListParams{ + ZoneID: cloudflare.F(m.ZoneID.ValueString()), + } + + return } diff --git a/internal/services/firewall_rule/data_source_schema.go b/internal/services/firewall_rule/data_source_schema.go index 486569ff6e..777901aeb4 100644 --- a/internal/services/firewall_rule/data_source_schema.go +++ b/internal/services/firewall_rule/data_source_schema.go @@ -6,11 +6,13 @@ import ( "context" "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -20,19 +22,18 @@ var _ datasource.DataSourceWithConfigValidators = (*FirewallRuleDataSource)(nil) func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the firewall rule.", + Computed: true, + }, "rule_id": schema.StringAttribute{ Description: "The unique identifier of the firewall rule.", - Required: true, + Optional: true, }, "zone_id": schema.StringAttribute{ Description: "Identifier", Required: true, }, - "id": schema.StringAttribute{ - Description: "The unique identifier of the firewall rule.", - Computed: true, - Optional: true, - }, "action": schema.StringAttribute{ Description: "The action to apply to a matched request. The `log` action is only available on an Enterprise plan.", Computed: true, @@ -85,36 +86,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, - "filter": schema.SingleNestedAttribute{ - Computed: true, - CustomType: customfield.NewNestedObjectType[FirewallRuleFilterDataSourceModel](ctx), - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Description: "The unique identifier of the filter.", - Computed: true, - }, - "description": schema.StringAttribute{ - Description: "An informative summary of the filter.", - Computed: true, - }, - "expression": schema.StringAttribute{ - Description: "The filter expression. For more information, refer to [Expressions](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/).", - Computed: true, - }, - "paused": schema.BoolAttribute{ - Description: "When true, indicates that the filter is currently paused.", - Computed: true, - }, - "ref": schema.StringAttribute{ - Description: "A short reference tag. Allows you to select related filters.", - Computed: true, - }, - "deleted": schema.BoolAttribute{ - Description: "When true, indicates that the firewall rule was deleted.", - Computed: true, - }, - }, - }, }, } } @@ -124,5 +95,7 @@ func (d *FirewallRuleDataSource) Schema(ctx context.Context, req datasource.Sche } func (d *FirewallRuleDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{} + return []datasource.ConfigValidator{ + datasourcevalidator.ExactlyOneOf(path.MatchRoot("rule_id"), path.MatchRoot("filter")), + } } diff --git a/internal/services/firewall_rule/model.go b/internal/services/firewall_rule/model.go index 4727ea2ca5..6439d07037 100644 --- a/internal/services/firewall_rule/model.go +++ b/internal/services/firewall_rule/model.go @@ -13,12 +13,11 @@ type FirewallRuleResultEnvelope struct { } type FirewallRuleModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` Action *FirewallRuleActionModel `tfsdk:"action" json:"action,required"` Filter *FirewallRuleFilterModel `tfsdk:"filter" json:"filter,required"` Description types.String `tfsdk:"description" json:"description,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` Paused types.Bool `tfsdk:"paused" json:"paused,computed"` Priority types.Float64 `tfsdk:"priority" json:"priority,computed"` Ref types.String `tfsdk:"ref" json:"ref,computed"` diff --git a/internal/services/firewall_rule/resource.go b/internal/services/firewall_rule/resource.go index 93e4857747..6016524081 100644 --- a/internal/services/firewall_rule/resource.go +++ b/internal/services/firewall_rule/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/firewall" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*FirewallRuleResource)(nil) var _ resource.ResourceWithModifyPlan = (*FirewallRuleResource)(nil) +var _ resource.ResourceWithImportState = (*FirewallRuleResource)(nil) func NewResource() resource.Resource { return &FirewallRuleResource{} @@ -118,7 +121,7 @@ func (r *FirewallRuleResource) Update(ctx context.Context, req resource.UpdateRe env := FirewallRuleResultEnvelope{*data} _, err = r.client.Firewall.Rules.Update( ctx, - data.RuleID.ValueString(), + data.ID.ValueString(), firewall.RuleUpdateParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -154,7 +157,7 @@ func (r *FirewallRuleResource) Read(ctx context.Context, req resource.ReadReques env := FirewallRuleResultEnvelope{*data} _, err := r.client.Firewall.Rules.Get( ctx, - data.RuleID.ValueString(), + data.ID.ValueString(), firewall.RuleGetParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -192,7 +195,7 @@ func (r *FirewallRuleResource) Delete(ctx context.Context, req resource.DeleteRe _, err := r.client.Firewall.Rules.Delete( ctx, - data.RuleID.ValueString(), + data.ID.ValueString(), firewall.RuleDeleteParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -206,6 +209,51 @@ func (r *FirewallRuleResource) Delete(ctx context.Context, req resource.DeleteRe resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *FirewallRuleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *FirewallRuleModel = new(FirewallRuleModel) + + path_zone_id := "" + path_rule_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_zone_id, + &path_rule_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.ZoneID = types.StringValue(path_zone_id) + data.ID = types.StringValue(path_rule_id) + + res := new(http.Response) + env := FirewallRuleResultEnvelope{*data} + _, err := r.client.Firewall.Rules.Get( + ctx, + path_rule_id, + firewall.RuleGetParams{ + ZoneID: cloudflare.F(path_zone_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *FirewallRuleResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/firewall_rule/schema.go b/internal/services/firewall_rule/schema.go index 708e90bb8b..da9f6855a4 100644 --- a/internal/services/firewall_rule/schema.go +++ b/internal/services/firewall_rule/schema.go @@ -22,16 +22,16 @@ var _ resource.ResourceWithConfigValidators = (*FirewallRuleResource)(nil) func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique identifier of the firewall rule.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, "zone_id": schema.StringAttribute{ Description: "Identifier", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "rule_id": schema.StringAttribute{ - Description: "The unique identifier of the firewall rule.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "action": schema.SingleNestedAttribute{ Description: "The action to perform when the threshold of matched traffic within the configured period is exceeded.", Required: true, @@ -101,10 +101,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "An informative summary of the firewall rule.", Computed: true, }, - "id": schema.StringAttribute{ - Description: "The unique identifier of the firewall rule.", - Computed: true, - }, "paused": schema.BoolAttribute{ Description: "When true, indicates that the firewall rule is currently paused.", Computed: true, diff --git a/internal/services/healthcheck/data_source_model.go b/internal/services/healthcheck/data_source_model.go index 57f52c4ec3..7f6f21bb13 100644 --- a/internal/services/healthcheck/data_source_model.go +++ b/internal/services/healthcheck/data_source_model.go @@ -17,10 +17,6 @@ type HealthcheckResultDataSourceEnvelope struct { Result HealthcheckDataSourceModel `json:"result,computed"` } -type HealthcheckResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[HealthcheckDataSourceModel] `json:"result,computed"` -} - type HealthcheckDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` HealthcheckID types.String `tfsdk:"healthcheck_id" path:"healthcheck_id,optional"` diff --git a/internal/services/hostname_tls_setting/data_source_model.go b/internal/services/hostname_tls_setting/data_source_model.go index b657f32e48..0785aec943 100644 --- a/internal/services/hostname_tls_setting/data_source_model.go +++ b/internal/services/hostname_tls_setting/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/hostnames" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +17,13 @@ type HostnameTLSSettingResultDataSourceEnvelope struct { } type HostnameTLSSettingDataSourceModel struct { - SettingID types.String `tfsdk:"setting_id" path:"setting_id,required"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + SettingID types.String `tfsdk:"setting_id" path:"setting_id,required"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + Hostname types.String `tfsdk:"hostname" json:"hostname,computed"` + Status types.String `tfsdk:"status" json:"status,computed"` + UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` + Value types.Float64 `tfsdk:"value" json:"value,computed"` } func (m *HostnameTLSSettingDataSourceModel) toReadParams(_ context.Context) (params hostnames.SettingTLSGetParams, diags diag.Diagnostics) { diff --git a/internal/services/hostname_tls_setting/data_source_schema.go b/internal/services/hostname_tls_setting/data_source_schema.go index 10ba486190..8a8151c227 100644 --- a/internal/services/hostname_tls_setting/data_source_schema.go +++ b/internal/services/hostname_tls_setting/data_source_schema.go @@ -5,6 +5,7 @@ package hostname_tls_setting import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -31,6 +32,28 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Identifier", Required: true, }, + "created_at": schema.StringAttribute{ + Description: "This is the time the tls setting was originally created for this hostname.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "hostname": schema.StringAttribute{ + Description: "The hostname for which the tls settings are set.", + Computed: true, + }, + "status": schema.StringAttribute{ + Description: "Deployment status for the given tls setting.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + Description: "This is the time the tls setting was updated.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "value": schema.Float64Attribute{ + Description: "The tls setting value.", + Computed: true, + }, }, } } diff --git a/internal/services/hostname_tls_setting/model.go b/internal/services/hostname_tls_setting/model.go index a5167117af..3492f4c5cc 100644 --- a/internal/services/hostname_tls_setting/model.go +++ b/internal/services/hostname_tls_setting/model.go @@ -17,7 +17,7 @@ type HostnameTLSSettingModel struct { SettingID types.String `tfsdk:"setting_id" path:"setting_id,required"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` Hostname types.String `tfsdk:"hostname" path:"hostname,optional"` - Value types.Float64 `tfsdk:"value" json:"value,required"` + Value types.Dynamic `tfsdk:"value" json:"value,required"` CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` Status types.String `tfsdk:"status" json:"status,computed"` UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` diff --git a/internal/services/hostname_tls_setting/resource_test.go b/internal/services/hostname_tls_setting/resource_test.go index d33fc17640..f4bf74645a 100644 --- a/internal/services/hostname_tls_setting/resource_test.go +++ b/internal/services/hostname_tls_setting/resource_test.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "testing" - "time" "github.com/cloudflare/cloudflare-go" "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" @@ -80,7 +79,29 @@ func TestAccCloudflareHostnameTLSSetting_Basic(t *testing.T) { ), }, }, - CheckDestroy: testAccCheckCloudflareHostnameTLSSettingDestroy, + }) +} + +func TestAccCloudflareHostnameTLSSetting_ListOfStrings(t *testing.T) { + t.Parallel() + zoneID := os.Getenv("CLOUDFLARE_ZONE_ID") + hostname := os.Getenv("CLOUDFLARE_DOMAIN") + rnd := utils.GenerateRandomResourceName() + resourceName := "cloudflare_hostname_tls_setting." + rnd + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.TestAccPreCheck(t) + }, + ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCheckCloudflareHostnameTLSSettingConfig_Ciphers(zoneID, fmt.Sprintf("%s.%s", rnd, hostname), "ciphers", rnd), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, consts.ZoneIDSchemaKey, zoneID), + ), + }, + }, }) } @@ -88,6 +109,10 @@ func testAccCheckCloudflareHostnameTLSSettingConfig(zoneID, hostname, setting, v return acctest.LoadTestCase("hostnametlssettingconfig.tf", zoneID, hostname, setting, value, rnd) } +func testAccCheckCloudflareHostnameTLSSettingConfig_Ciphers(zoneID, hostname, setting, rnd string) string { + return acctest.LoadTestCase("ciphers.tf", zoneID, hostname, setting, rnd) +} + func testAccCheckCloudflareHostnameTLSSettingExists(name string, htlss *cloudflare.HostnameTLSSetting) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] @@ -119,22 +144,3 @@ func testAccCheckCloudflareHostnameTLSSettingExists(name string, htlss *cloudfla return nil } } - -func testAccCheckCloudflareHostnameTLSSettingDestroy(s *terraform.State) error { - // sleep in order to allow htlss to enter active state before being deleted - // lintignore: R018 - time.Sleep(time.Second) - client, clientErr := acctest.SharedV1Client() // TODO(terraform): replace with SharedV2Clent - if clientErr != nil { - tflog.Error(context.TODO(), fmt.Sprintf("failed to create Cloudflare client: %s", clientErr)) - } - for _, rs := range s.RootModule().Resources { - zoneID := rs.Primary.Attributes[consts.ZoneIDSchemaKey] - zoneIDrc := cloudflare.ZoneIdentifier(zoneID) - _, err := client.DeleteHostnameTLSSetting(context.Background(), zoneIDrc, cloudflare.DeleteHostnameTLSSettingParams{Hostname: rs.Primary.ID, Setting: "min_tls_version"}) - if err == nil { - return fmt.Errorf("error deleting hostname tls setting in zone %q: %w", zoneID, err) - } - } - return nil -} diff --git a/internal/services/hostname_tls_setting/schema.go b/internal/services/hostname_tls_setting/schema.go index 8f7cb7d252..6db1d2da50 100644 --- a/internal/services/hostname_tls_setting/schema.go +++ b/internal/services/hostname_tls_setting/schema.go @@ -53,7 +53,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Optional: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "value": schema.Float64Attribute{ + "value": schema.DynamicAttribute{ Description: "The tls setting value.", Required: true, }, diff --git a/internal/services/hostname_tls_setting/testdata/ciphers.tf b/internal/services/hostname_tls_setting/testdata/ciphers.tf new file mode 100644 index 0000000000..b5737ceda8 --- /dev/null +++ b/internal/services/hostname_tls_setting/testdata/ciphers.tf @@ -0,0 +1,10 @@ + +resource "cloudflare_hostname_tls_setting" "%[4]s" { + zone_id = "%[1]s" + hostname = "%[2]s" + setting_id = "%[3]s" + value = [ + "AES128-SHA", + "ECDHE-RSA-AES256-SHA", + ] +} diff --git a/internal/services/hyperdrive_config/model.go b/internal/services/hyperdrive_config/model.go index e973bd1a52..42e1683890 100644 --- a/internal/services/hyperdrive_config/model.go +++ b/internal/services/hyperdrive_config/model.go @@ -43,7 +43,7 @@ type HyperdriveConfigOriginModel struct { } type HyperdriveConfigCachingModel struct { - Disabled types.Bool `tfsdk:"disabled" json:"disabled,optional"` + Disabled types.Bool `tfsdk:"disabled" json:"disabled,computed_optional"` MaxAge types.Int64 `tfsdk:"max_age" json:"max_age,optional"` StaleWhileRevalidate types.Int64 `tfsdk:"stale_while_revalidate" json:"stale_while_revalidate,optional"` } diff --git a/internal/services/ip_ranges/data_source.go b/internal/services/ip_ranges/data_source.go new file mode 100644 index 0000000000..6bf0f7f60c --- /dev/null +++ b/internal/services/ip_ranges/data_source.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package ip_ranges + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type IPRangesDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*IPRangesDataSource)(nil) + +func NewIPRangesDataSource() datasource.DataSource { + return &IPRangesDataSource{} +} + +func (d *IPRangesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_ip_ranges" +} + +func (d *IPRangesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *IPRangesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *IPRangesDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := IPRangesResultDataSourceEnvelope{*data} + _, err := d.client.IPs.List( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/ip_ranges/data_source_model.go b/internal/services/ip_ranges/data_source_model.go new file mode 100644 index 0000000000..b92190bf4c --- /dev/null +++ b/internal/services/ip_ranges/data_source_model.go @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package ip_ranges + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4/ips" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type IPRangesResultDataSourceEnvelope struct { + Result IPRangesDataSourceModel `json:"result,computed"` +} + +type IPRangesDataSourceModel struct { + Networks types.String `tfsdk:"networks" query:"networks,optional"` + Etag types.String `tfsdk:"etag" json:"etag,computed"` + IPV4CIDRs customfield.List[types.String] `tfsdk:"ipv4_cidrs" json:"ipv4_cidrs,computed"` + IPV6CIDRs customfield.List[types.String] `tfsdk:"ipv6_cidrs" json:"ipv6_cidrs,computed"` + JDCloudCIDRs customfield.List[types.String] `tfsdk:"jdcloud_cidrs" json:"jdcloud_cidrs,computed"` +} + +func (m *IPRangesDataSourceModel) toReadParams(_ context.Context) (params ips.IPListParams, diags diag.Diagnostics) { + params = ips.IPListParams{} + + return +} diff --git a/internal/services/ip_ranges/data_source_schema.go b/internal/services/ip_ranges/data_source_schema.go new file mode 100644 index 0000000000..d170388472 --- /dev/null +++ b/internal/services/ip_ranges/data_source_schema.go @@ -0,0 +1,55 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package ip_ranges + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*IPRangesDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "networks": schema.StringAttribute{ + Description: "Specified as `jdcloud` to list IPs used by JD Cloud data centers.", + Optional: true, + }, + "etag": schema.StringAttribute{ + Description: "A digest of the IP data. Useful for determining if the data has changed.", + Computed: true, + }, + "ipv4_cidrs": schema.ListAttribute{ + Description: "List of Cloudflare IPv4 CIDR addresses.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "ipv6_cidrs": schema.ListAttribute{ + Description: "List of Cloudflare IPv6 CIDR addresses.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "jdcloud_cidrs": schema.ListAttribute{ + Description: "List IPv4 and IPv6 CIDRs, only populated if `?networks=jdcloud` is used.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, + } +} + +func (d *IPRangesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *IPRangesDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/ip_ranges/data_source_schema_test.go b/internal/services/ip_ranges/data_source_schema_test.go new file mode 100644 index 0000000000..394f21caaf --- /dev/null +++ b/internal/services/ip_ranges/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package ip_ranges_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/ip_ranges" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestIPRangesDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*ip_ranges.IPRangesDataSourceModel)(nil) + schema := ip_ranges.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/keyless_certificate/data_source_model.go b/internal/services/keyless_certificate/data_source_model.go index b4514b36c4..2020a530fc 100644 --- a/internal/services/keyless_certificate/data_source_model.go +++ b/internal/services/keyless_certificate/data_source_model.go @@ -17,10 +17,6 @@ type KeylessCertificateResultDataSourceEnvelope struct { Result KeylessCertificateDataSourceModel `json:"result,computed"` } -type KeylessCertificateResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[KeylessCertificateDataSourceModel] `json:"result,computed"` -} - type KeylessCertificateDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` KeylessCertificateID types.String `tfsdk:"keyless_certificate_id" path:"keyless_certificate_id,optional"` diff --git a/internal/services/list/data_source_model.go b/internal/services/list/data_source_model.go index 59317affff..0e964feece 100644 --- a/internal/services/list/data_source_model.go +++ b/internal/services/list/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/rules" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type ListResultDataSourceEnvelope struct { Result ListDataSourceModel `json:"result,computed"` } -type ListResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ListDataSourceModel] `json:"result,computed"` -} - type ListDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ListID types.String `tfsdk:"list_id" path:"list_id,optional"` diff --git a/internal/services/list_item/model.go b/internal/services/list_item/model.go index 1b268124d0..06cf2ede76 100644 --- a/internal/services/list_item/model.go +++ b/internal/services/list_item/model.go @@ -15,12 +15,12 @@ type ListItemResultEnvelope struct { type ListItemModel struct { ListID types.String `tfsdk:"list_id" path:"list_id,required"` AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` - ItemID types.String `tfsdk:"item_id" path:"item_id,computed"` + ID types.String `tfsdk:"id" path:"item_id,computed"` ASN types.Int64 `tfsdk:"asn" json:"asn,optional"` Comment types.String `tfsdk:"comment" json:"comment,optional"` IP types.String `tfsdk:"ip" json:"ip,optional"` - Hostname customfield.NestedObject[ListItemHostnameModel] `tfsdk:"hostname" json:"hostname,computed_optional"` - Redirect customfield.NestedObject[ListItemRedirectModel] `tfsdk:"redirect" json:"redirect,computed_optional"` + Hostname customfield.NestedObject[ListItemHostnameModel] `tfsdk:"hostname" json:"hostname,optional"` + Redirect customfield.NestedObject[ListItemRedirectModel] `tfsdk:"redirect" json:"redirect,optional"` OperationID types.String `tfsdk:"operation_id" json:"operation_id,computed"` ModifiedOn types.String `tfsdk:"modified_on" json:"modified_on,computed"` CreatedOn types.String `tfsdk:"created_on" json:"created_on,computed"` diff --git a/internal/services/list_item/resource.go b/internal/services/list_item/resource.go index 33d678b61d..b4772135f1 100644 --- a/internal/services/list_item/resource.go +++ b/internal/services/list_item/resource.go @@ -115,7 +115,7 @@ func (r *ListItemResource) Create(ctx context.Context, req resource.CreateReques } findListItem, _ := io.ReadAll(findItemRes.Body) itemID := gjson.Get(string(findListItem), "result.0.id") - data.ItemID = types.StringValue(itemID.String()) + data.ID = types.StringValue(itemID.String()) env := ListItemResultEnvelope{*data} listItemRes := new(http.Response) @@ -123,7 +123,7 @@ func (r *ListItemResource) Create(ctx context.Context, req resource.CreateReques ctx, data.AccountID.ValueString(), data.ListID.ValueString(), - data.ItemID.ValueString(), + data.ID.ValueString(), option.WithResponseBodyInto(&listItemRes), option.WithMiddleware(logging.Middleware(ctx)), ) @@ -207,7 +207,7 @@ func (r *ListItemResource) Read(ctx context.Context, req resource.ReadRequest, r ctx, data.AccountID.ValueString(), data.ListID.ValueString(), - data.ItemID.ValueString(), + data.ID.ValueString(), option.WithResponseBodyInto(&res), option.WithMiddleware(logging.Middleware(ctx)), ) @@ -242,7 +242,7 @@ func (r *ListItemResource) Delete(ctx context.Context, req resource.DeleteReques deletePayload := bodyDeletePayload{ Items: []bodyDeleteItems{{ - ID: data.ItemID.ValueString(), + ID: data.ID.ValueString(), }}, } deleteBody, _ := json.Marshal(deletePayload) diff --git a/internal/services/list_item/schema.go b/internal/services/list_item/schema.go index 82927ac1ce..312fe22c90 100644 --- a/internal/services/list_item/schema.go +++ b/internal/services/list_item/schema.go @@ -31,7 +31,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Optional: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "item_id": schema.StringAttribute{ + "id": schema.StringAttribute{ Description: "The unique ID of the item in the List.", Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, @@ -42,16 +42,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "comment": schema.StringAttribute{ Description: "An informative summary of the list item.", - Computed: true, + Optional: true, }, "created_on": schema.StringAttribute{ Description: "The RFC 3339 timestamp of when the item was created.", Computed: true, }, - "id": schema.StringAttribute{ - Description: "The unique ID of the list.", - Computed: true, - }, "modified_on": schema.StringAttribute{ Description: "The RFC 3339 timestamp of when the item was last modified.", Computed: true, diff --git a/internal/services/load_balancer/data_source_model.go b/internal/services/load_balancer/data_source_model.go index edc6897fa8..37dd995ee4 100644 --- a/internal/services/load_balancer/data_source_model.go +++ b/internal/services/load_balancer/data_source_model.go @@ -16,10 +16,6 @@ type LoadBalancerResultDataSourceEnvelope struct { Result LoadBalancerDataSourceModel `json:"result,computed"` } -type LoadBalancerResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[LoadBalancerDataSourceModel] `json:"result,computed"` -} - type LoadBalancerDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` LoadBalancerID types.String `tfsdk:"load_balancer_id" path:"load_balancer_id,optional"` @@ -39,7 +35,7 @@ type LoadBalancerDataSourceModel struct { DefaultPools customfield.List[types.String] `tfsdk:"default_pools" json:"default_pools,computed"` Networks customfield.List[types.String] `tfsdk:"networks" json:"networks,computed"` POPPools customfield.Map[customfield.List[types.String]] `tfsdk:"pop_pools" json:"pop_pools,computed_optional"` - RegionPools customfield.Map[customfield.List[types.String]] `tfsdk:"region_pools" json:"region_pools,computed"` + RegionPools customfield.Map[customfield.List[types.String]] `tfsdk:"region_pools" json:"region_pools,computed_optional"` AdaptiveRouting customfield.NestedObject[LoadBalancerAdaptiveRoutingDataSourceModel] `tfsdk:"adaptive_routing" json:"adaptive_routing,computed"` LocationStrategy customfield.NestedObject[LoadBalancerLocationStrategyDataSourceModel] `tfsdk:"location_strategy" json:"location_strategy,computed"` RandomSteering customfield.NestedObject[LoadBalancerRandomSteeringDataSourceModel] `tfsdk:"random_steering" json:"random_steering,computed"` diff --git a/internal/services/load_balancer_monitor/data_source_model.go b/internal/services/load_balancer_monitor/data_source_model.go index 5fed2aa9f5..848f37ef42 100644 --- a/internal/services/load_balancer_monitor/data_source_model.go +++ b/internal/services/load_balancer_monitor/data_source_model.go @@ -16,10 +16,6 @@ type LoadBalancerMonitorResultDataSourceEnvelope struct { Result LoadBalancerMonitorDataSourceModel `json:"result,computed"` } -type LoadBalancerMonitorResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[LoadBalancerMonitorDataSourceModel] `json:"result,computed"` -} - type LoadBalancerMonitorDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` MonitorID types.String `tfsdk:"monitor_id" path:"monitor_id,optional"` diff --git a/internal/services/load_balancer_pool/data_source.go b/internal/services/load_balancer_pool/data_source.go index 2665044dd7..ade636d2df 100644 --- a/internal/services/load_balancer_pool/data_source.go +++ b/internal/services/load_balancer_pool/data_source.go @@ -64,7 +64,7 @@ func (d *LoadBalancerPoolDataSource) Read(ctx context.Context, req datasource.Re return } - env := LoadBalancerPoolResultListDataSourceEnvelope{} + env := LoadBalancerPoolsResultListDataSourceEnvelope{} page, err := d.client.LoadBalancers.Pools.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *LoadBalancerPoolDataSource) Read(ctx context.Context, req datasource.Re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.PoolID = ts[0].PoolID + data.PoolID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/load_balancer_pool/data_source_model.go b/internal/services/load_balancer_pool/data_source_model.go index 796e95d8f7..543e40f761 100644 --- a/internal/services/load_balancer_pool/data_source_model.go +++ b/internal/services/load_balancer_pool/data_source_model.go @@ -17,10 +17,6 @@ type LoadBalancerPoolResultDataSourceEnvelope struct { Result LoadBalancerPoolDataSourceModel `json:"result,computed"` } -type LoadBalancerPoolResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[LoadBalancerPoolDataSourceModel] `json:"result,computed"` -} - type LoadBalancerPoolDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PoolID types.String `tfsdk:"pool_id" path:"pool_id,optional"` diff --git a/internal/services/logpush_dataset_job/data_source_model.go b/internal/services/logpush_dataset_job/data_source_model.go index 65f5b3c97a..1de352d403 100644 --- a/internal/services/logpush_dataset_job/data_source_model.go +++ b/internal/services/logpush_dataset_job/data_source_model.go @@ -7,6 +7,8 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/logpush" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,9 +18,24 @@ type LogpushDatasetJobResultDataSourceEnvelope struct { } type LogpushDatasetJobDataSourceModel struct { - DatasetID types.String `tfsdk:"dataset_id" path:"dataset_id,required"` - AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + DatasetID types.String `tfsdk:"dataset_id" path:"dataset_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + Dataset types.String `tfsdk:"dataset" json:"dataset,computed"` + DestinationConf types.String `tfsdk:"destination_conf" json:"destination_conf,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + ErrorMessage timetypes.RFC3339 `tfsdk:"error_message" json:"error_message,computed" format:"date-time"` + Frequency types.String `tfsdk:"frequency" json:"frequency,computed"` + ID types.Int64 `tfsdk:"id" json:"id,computed"` + Kind types.String `tfsdk:"kind" json:"kind,computed"` + LastComplete timetypes.RFC3339 `tfsdk:"last_complete" json:"last_complete,computed" format:"date-time"` + LastError timetypes.RFC3339 `tfsdk:"last_error" json:"last_error,computed" format:"date-time"` + LogpullOptions types.String `tfsdk:"logpull_options" json:"logpull_options,computed"` + MaxUploadBytes types.Int64 `tfsdk:"max_upload_bytes" json:"max_upload_bytes,computed"` + MaxUploadIntervalSeconds types.Int64 `tfsdk:"max_upload_interval_seconds" json:"max_upload_interval_seconds,computed"` + MaxUploadRecords types.Int64 `tfsdk:"max_upload_records" json:"max_upload_records,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + OutputOptions customfield.NestedObject[LogpushDatasetJobOutputOptionsDataSourceModel] `tfsdk:"output_options" json:"output_options,computed"` } func (m *LogpushDatasetJobDataSourceModel) toReadParams(_ context.Context) (params logpush.DatasetJobGetParams, diags diag.Diagnostics) { @@ -32,3 +49,18 @@ func (m *LogpushDatasetJobDataSourceModel) toReadParams(_ context.Context) (para return } + +type LogpushDatasetJobOutputOptionsDataSourceModel struct { + BatchPrefix types.String `tfsdk:"batch_prefix" json:"batch_prefix,computed"` + BatchSuffix types.String `tfsdk:"batch_suffix" json:"batch_suffix,computed"` + Cve2021_4428 types.Bool `tfsdk:"cve_2021_4428" json:"CVE-2021-4428,computed"` + FieldDelimiter types.String `tfsdk:"field_delimiter" json:"field_delimiter,computed"` + FieldNames customfield.List[types.String] `tfsdk:"field_names" json:"field_names,computed"` + OutputType types.String `tfsdk:"output_type" json:"output_type,computed"` + RecordDelimiter types.String `tfsdk:"record_delimiter" json:"record_delimiter,computed"` + RecordPrefix types.String `tfsdk:"record_prefix" json:"record_prefix,computed"` + RecordSuffix types.String `tfsdk:"record_suffix" json:"record_suffix,computed"` + RecordTemplate types.String `tfsdk:"record_template" json:"record_template,computed"` + SampleRate types.Float64 `tfsdk:"sample_rate" json:"sample_rate,computed"` + TimestampFormat types.String `tfsdk:"timestamp_format" json:"timestamp_format,computed"` +} diff --git a/internal/services/logpush_dataset_job/data_source_schema.go b/internal/services/logpush_dataset_job/data_source_schema.go index a02a79ffb5..59752c18d4 100644 --- a/internal/services/logpush_dataset_job/data_source_schema.go +++ b/internal/services/logpush_dataset_job/data_source_schema.go @@ -5,10 +5,17 @@ package logpush_dataset_job import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/float64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*LogpushDatasetJobDataSource)(nil) @@ -28,6 +35,153 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.", Optional: true, }, + "dataset": schema.StringAttribute{ + Description: "Name of the dataset. A list of supported datasets can be found on the [Developer Docs](https://developers.cloudflare.com/logs/reference/log-fields/).", + Computed: true, + }, + "destination_conf": schema.StringAttribute{ + Description: "Uniquely identifies a resource (such as an s3 bucket) where data will be pushed. Additional configuration parameters supported by the destination may be included.", + Computed: true, + }, + "enabled": schema.BoolAttribute{ + Description: "Flag that indicates if the job is enabled.", + Computed: true, + }, + "error_message": schema.StringAttribute{ + Description: "If not null, the job is currently failing. Failures are usually repetitive (example: no permissions to write to destination bucket). Only the last failure is recorded. On successful execution of a job the error_message and last_error are set to null.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "frequency": schema.StringAttribute{ + Description: "This field is deprecated. Please use `max_upload_*` parameters instead. The frequency at which Cloudflare sends batches of logs to your destination. Setting frequency to high sends your logs in larger quantities of smaller files. Setting frequency to low sends logs in smaller quantities of larger files.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("high", "low"), + }, + }, + "id": schema.Int64Attribute{ + Description: "Unique id of the job.", + Computed: true, + Validators: []validator.Int64{ + int64validator.AtLeast(1), + }, + }, + "kind": schema.StringAttribute{ + Description: "The kind parameter (optional) is used to differentiate between Logpush and Edge Log Delivery jobs. Currently, Edge Log Delivery is only supported for the `http_requests` dataset.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("edge"), + }, + }, + "last_complete": schema.StringAttribute{ + Description: "Records the last time for which logs have been successfully pushed. If the last successful push was for logs range 2018-07-23T10:00:00Z to 2018-07-23T10:01:00Z then the value of this field will be 2018-07-23T10:01:00Z. If the job has never run or has just been enabled and hasn't run yet then the field will be empty.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "last_error": schema.StringAttribute{ + Description: "Records the last time the job failed. If not null, the job is currently failing. If null, the job has either never failed or has run successfully at least once since last failure. See also the error_message field.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "logpull_options": schema.StringAttribute{ + Description: "This field is deprecated. Use `output_options` instead. Configuration string. It specifies things like requested fields and timestamp formats. If migrating from the logpull api, copy the url (full url or just the query string) of your call here, and logpush will keep on making this call for you, setting start and end times appropriately.", + Computed: true, + }, + "max_upload_bytes": schema.Int64Attribute{ + Description: "The maximum uncompressed file size of a batch of logs. This setting value must be between `5 MB` and `1 GB`, or `0` to disable it. Note that you cannot set a minimum file size; this means that log files may be much smaller than this batch size. This parameter is not available for jobs with `edge` as its kind.", + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(5000000, 1000000000), + }, + }, + "max_upload_interval_seconds": schema.Int64Attribute{ + Description: "The maximum interval in seconds for log batches. This setting must be between 30 and 300 seconds (5 minutes), or `0` to disable it. Note that you cannot specify a minimum interval for log batches; this means that log files may be sent in shorter intervals than this. This parameter is only used for jobs with `edge` as its kind.", + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(30, 300), + }, + }, + "max_upload_records": schema.Int64Attribute{ + Description: "The maximum number of log lines per batch. This setting must be between 1000 and 1,000,000 lines, or `0` to disable it. Note that you cannot specify a minimum number of log lines per batch; this means that log files may contain many fewer lines than this. This parameter is not available for jobs with `edge` as its kind.", + Computed: true, + Validators: []validator.Int64{ + int64validator.Between(1000, 1000000), + }, + }, + "name": schema.StringAttribute{ + Description: "Optional human readable job name. Not unique. Cloudflare suggests that you set this to a meaningful string, like the domain name, to make it easier to identify your job.", + Computed: true, + }, + "output_options": schema.SingleNestedAttribute{ + Description: "The structured replacement for `logpull_options`. When including this field, the `logpull_option` field will be ignored.", + Computed: true, + CustomType: customfield.NewNestedObjectType[LogpushDatasetJobOutputOptionsDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "batch_prefix": schema.StringAttribute{ + Description: "String to be prepended before each batch.", + Computed: true, + }, + "batch_suffix": schema.StringAttribute{ + Description: "String to be appended after each batch.", + Computed: true, + }, + "cve_2021_4428": schema.BoolAttribute{ + Description: "If set to true, will cause all occurrences of `${` in the generated files to be replaced with `x{`.", + Computed: true, + }, + "field_delimiter": schema.StringAttribute{ + Description: "String to join fields. This field be ignored when `record_template` is set.", + Computed: true, + }, + "field_names": schema.ListAttribute{ + Description: "List of field names to be included in the Logpush output. For the moment, there is no option to add all fields at once, so you must specify all the fields names you are interested in.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "output_type": schema.StringAttribute{ + Description: "Specifies the output type, such as `ndjson` or `csv`. This sets default values for the rest of the settings, depending on the chosen output type. Some formatting rules, like string quoting, are different between output types.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("ndjson", "csv"), + }, + }, + "record_delimiter": schema.StringAttribute{ + Description: "String to be inserted in-between the records as separator.", + Computed: true, + }, + "record_prefix": schema.StringAttribute{ + Description: "String to be prepended before each record.", + Computed: true, + }, + "record_suffix": schema.StringAttribute{ + Description: "String to be appended after each record.", + Computed: true, + }, + "record_template": schema.StringAttribute{ + Description: "String to use as template for each record instead of the default comma-separated list. All fields used in the template must be present in `field_names` as well, otherwise they will end up as null. Format as a Go `text/template` without any standard functions, like conditionals, loops, sub-templates, etc.", + Computed: true, + }, + "sample_rate": schema.Float64Attribute{ + Description: "Floating number to specify sampling rate. Sampling is applied on top of filtering, and regardless of the current `sample_interval` of the data.", + Computed: true, + Validators: []validator.Float64{ + float64validator.Between(0, 1), + }, + }, + "timestamp_format": schema.StringAttribute{ + Description: "String to specify the format for timestamps, such as `unixnano`, `unix`, or `rfc3339`.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "unixnano", + "unix", + "rfc3339", + ), + }, + }, + }, + }, }, } } diff --git a/internal/services/logpush_job/data_source_model.go b/internal/services/logpush_job/data_source_model.go index 56928fcaa2..05bcc844b4 100644 --- a/internal/services/logpush_job/data_source_model.go +++ b/internal/services/logpush_job/data_source_model.go @@ -17,10 +17,6 @@ type LogpushJobResultDataSourceEnvelope struct { Result LogpushJobDataSourceModel `json:"result,computed"` } -type LogpushJobResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[LogpushJobDataSourceModel] `json:"result,computed"` -} - type LogpushJobDataSourceModel struct { ID types.Int64 `tfsdk:"id" json:"-,computed"` JobID types.Int64 `tfsdk:"job_id" path:"job_id,optional"` diff --git a/internal/services/magic_network_monitoring_rule/data_source_model.go b/internal/services/magic_network_monitoring_rule/data_source_model.go index 619592f927..7fb9b395ad 100644 --- a/internal/services/magic_network_monitoring_rule/data_source_model.go +++ b/internal/services/magic_network_monitoring_rule/data_source_model.go @@ -16,10 +16,6 @@ type MagicNetworkMonitoringRuleResultDataSourceEnvelope struct { Result MagicNetworkMonitoringRuleDataSourceModel `json:"result,computed"` } -type MagicNetworkMonitoringRuleResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[MagicNetworkMonitoringRuleDataSourceModel] `json:"result,computed"` -} - type MagicNetworkMonitoringRuleDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` diff --git a/internal/services/magic_transit_connector/data_source_model.go b/internal/services/magic_transit_connector/data_source_model.go index 680367d7a4..f4ea4d8625 100644 --- a/internal/services/magic_transit_connector/data_source_model.go +++ b/internal/services/magic_transit_connector/data_source_model.go @@ -16,10 +16,6 @@ type MagicTransitConnectorResultDataSourceEnvelope struct { Result MagicTransitConnectorDataSourceModel `json:"result,computed"` } -type MagicTransitConnectorResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[MagicTransitConnectorDataSourceModel] `json:"result,computed"` -} - type MagicTransitConnectorDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ConnectorID types.String `tfsdk:"connector_id" path:"connector_id,optional"` diff --git a/internal/services/magic_transit_site/data_source.go b/internal/services/magic_transit_site/data_source.go index b1380861fb..ee5d808477 100644 --- a/internal/services/magic_transit_site/data_source.go +++ b/internal/services/magic_transit_site/data_source.go @@ -64,7 +64,7 @@ func (d *MagicTransitSiteDataSource) Read(ctx context.Context, req datasource.Re return } - env := MagicTransitSiteResultListDataSourceEnvelope{} + env := MagicTransitSitesResultListDataSourceEnvelope{} page, err := d.client.MagicTransit.Sites.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *MagicTransitSiteDataSource) Read(ctx context.Context, req datasource.Re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.SiteID = ts[0].SiteID + data.SiteID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/magic_transit_site/data_source_model.go b/internal/services/magic_transit_site/data_source_model.go index b1dc058184..fa0fe19879 100644 --- a/internal/services/magic_transit_site/data_source_model.go +++ b/internal/services/magic_transit_site/data_source_model.go @@ -16,10 +16,6 @@ type MagicTransitSiteResultDataSourceEnvelope struct { Result MagicTransitSiteDataSourceModel `json:"result,computed"` } -type MagicTransitSiteResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[MagicTransitSiteDataSourceModel] `json:"result,computed"` -} - type MagicTransitSiteDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` SiteID types.String `tfsdk:"site_id" path:"site_id,optional"` @@ -46,8 +42,8 @@ func (m *MagicTransitSiteDataSourceModel) toListParams(_ context.Context) (param AccountID: cloudflare.F(m.AccountID.ValueString()), } - if !m.Filter.ConnectorIdentifier.IsNull() { - params.ConnectorIdentifier = cloudflare.F(m.Filter.ConnectorIdentifier.ValueString()) + if !m.Filter.Connectorid.IsNull() { + params.Connectorid = cloudflare.F(m.Filter.Connectorid.ValueString()) } return @@ -59,5 +55,5 @@ type MagicTransitSiteLocationDataSourceModel struct { } type MagicTransitSiteFindOneByDataSourceModel struct { - ConnectorIdentifier types.String `tfsdk:"connector_identifier" query:"connector_identifier,optional"` + Connectorid types.String `tfsdk:"connectorid" query:"connectorid,optional"` } diff --git a/internal/services/magic_transit_site/data_source_schema.go b/internal/services/magic_transit_site/data_source_schema.go index 6ae3afac69..363f3bba1c 100644 --- a/internal/services/magic_transit_site/data_source_schema.go +++ b/internal/services/magic_transit_site/data_source_schema.go @@ -66,7 +66,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "filter": schema.SingleNestedAttribute{ Optional: true, Attributes: map[string]schema.Attribute{ - "connector_identifier": schema.StringAttribute{ + "connectorid": schema.StringAttribute{ Description: "Identifier", Optional: true, }, diff --git a/internal/services/magic_transit_site/list_data_source_model.go b/internal/services/magic_transit_site/list_data_source_model.go index 54ef70bc2e..40660be7a3 100644 --- a/internal/services/magic_transit_site/list_data_source_model.go +++ b/internal/services/magic_transit_site/list_data_source_model.go @@ -17,10 +17,10 @@ type MagicTransitSitesResultListDataSourceEnvelope struct { } type MagicTransitSitesDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - ConnectorIdentifier types.String `tfsdk:"connector_identifier" query:"connector_identifier,optional"` - MaxItems types.Int64 `tfsdk:"max_items"` - Result customfield.NestedObjectList[MagicTransitSitesResultDataSourceModel] `tfsdk:"result"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Connectorid types.String `tfsdk:"connectorid" query:"connectorid,optional"` + MaxItems types.Int64 `tfsdk:"max_items"` + Result customfield.NestedObjectList[MagicTransitSitesResultDataSourceModel] `tfsdk:"result"` } func (m *MagicTransitSitesDataSourceModel) toListParams(_ context.Context) (params magic_transit.SiteListParams, diags diag.Diagnostics) { @@ -28,8 +28,8 @@ func (m *MagicTransitSitesDataSourceModel) toListParams(_ context.Context) (para AccountID: cloudflare.F(m.AccountID.ValueString()), } - if !m.ConnectorIdentifier.IsNull() { - params.ConnectorIdentifier = cloudflare.F(m.ConnectorIdentifier.ValueString()) + if !m.Connectorid.IsNull() { + params.Connectorid = cloudflare.F(m.Connectorid.ValueString()) } return diff --git a/internal/services/magic_transit_site/list_data_source_schema.go b/internal/services/magic_transit_site/list_data_source_schema.go index 96fea88855..2cabc7ade8 100644 --- a/internal/services/magic_transit_site/list_data_source_schema.go +++ b/internal/services/magic_transit_site/list_data_source_schema.go @@ -21,7 +21,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "Identifier", Required: true, }, - "connector_identifier": schema.StringAttribute{ + "connectorid": schema.StringAttribute{ Description: "Identifier", Optional: true, }, diff --git a/internal/services/magic_transit_site_acl/data_source_model.go b/internal/services/magic_transit_site_acl/data_source_model.go index cb8b214a9c..317b974e8e 100644 --- a/internal/services/magic_transit_site_acl/data_source_model.go +++ b/internal/services/magic_transit_site_acl/data_source_model.go @@ -16,10 +16,6 @@ type MagicTransitSiteACLResultDataSourceEnvelope struct { Result MagicTransitSiteACLDataSourceModel `json:"result,computed"` } -type MagicTransitSiteACLResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[MagicTransitSiteACLDataSourceModel] `json:"result,computed"` -} - type MagicTransitSiteACLDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ACLID types.String `tfsdk:"acl_id" path:"acl_id,optional"` diff --git a/internal/services/magic_transit_site_lan/data_source_model.go b/internal/services/magic_transit_site_lan/data_source_model.go index cf5eef680e..3459f5d4e0 100644 --- a/internal/services/magic_transit_site_lan/data_source_model.go +++ b/internal/services/magic_transit_site_lan/data_source_model.go @@ -17,11 +17,11 @@ type MagicTransitSiteLANResultDataSourceEnvelope struct { } type MagicTransitSiteLANDataSourceModel struct { + ID types.String `tfsdk:"id" json:"-,computed"` + LANID types.String `tfsdk:"lan_id" path:"lan_id,optional"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - LANID types.String `tfsdk:"lan_id" path:"lan_id,required"` SiteID types.String `tfsdk:"site_id" path:"site_id,computed"` HaLink types.Bool `tfsdk:"ha_link" json:"ha_link,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` Name types.String `tfsdk:"name" json:"name,computed"` Physport types.Int64 `tfsdk:"physport" json:"physport,computed"` VlanTag types.Int64 `tfsdk:"vlan_tag" json:"vlan_tag,computed"` @@ -38,6 +38,14 @@ func (m *MagicTransitSiteLANDataSourceModel) toReadParams(_ context.Context) (pa return } +func (m *MagicTransitSiteLANDataSourceModel) toListParams(_ context.Context) (params magic_transit.SiteLANListParams, diags diag.Diagnostics) { + params = magic_transit.SiteLANListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + type MagicTransitSiteLANNatDataSourceModel struct { StaticPrefix types.String `tfsdk:"static_prefix" json:"static_prefix,computed"` } @@ -65,8 +73,9 @@ type MagicTransitSiteLANStaticAddressingDHCPRelayDataSourceModel struct { } type MagicTransitSiteLANStaticAddressingDHCPServerDataSourceModel struct { - DHCPPoolEnd types.String `tfsdk:"dhcp_pool_end" json:"dhcp_pool_end,computed"` - DHCPPoolStart types.String `tfsdk:"dhcp_pool_start" json:"dhcp_pool_start,computed"` - DNSServer types.String `tfsdk:"dns_server" json:"dns_server,computed"` - Reservations customfield.Map[types.String] `tfsdk:"reservations" json:"reservations,computed"` + DHCPPoolEnd types.String `tfsdk:"dhcp_pool_end" json:"dhcp_pool_end,computed"` + DHCPPoolStart types.String `tfsdk:"dhcp_pool_start" json:"dhcp_pool_start,computed"` + DNSServer types.String `tfsdk:"dns_server" json:"dns_server,computed"` + DNSServers customfield.List[types.String] `tfsdk:"dns_servers" json:"dns_servers,computed"` + Reservations customfield.Map[types.String] `tfsdk:"reservations" json:"reservations,computed"` } diff --git a/internal/services/magic_transit_site_lan/data_source_schema.go b/internal/services/magic_transit_site_lan/data_source_schema.go index 9ab3881fd0..920bd09188 100644 --- a/internal/services/magic_transit_site_lan/data_source_schema.go +++ b/internal/services/magic_transit_site_lan/data_source_schema.go @@ -16,11 +16,15 @@ var _ datasource.DataSourceWithConfigValidators = (*MagicTransitSiteLANDataSourc func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ - "account_id": schema.StringAttribute{ + "id": schema.StringAttribute{ Description: "Identifier", - Required: true, + Computed: true, }, "lan_id": schema.StringAttribute{ + Description: "Identifier", + Optional: true, + }, + "account_id": schema.StringAttribute{ Description: "Identifier", Required: true, }, @@ -32,10 +36,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "mark true to use this LAN for HA probing. only works for site with HA turned on. only one LAN can be set as the ha_link.", Computed: true, }, - "id": schema.StringAttribute{ - Description: "Identifier", - Computed: true, - }, "name": schema.StringAttribute{ Computed: true, }, @@ -119,6 +119,11 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "A valid IPv4 address.", Computed: true, }, + "dns_servers": schema.ListAttribute{ + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, "reservations": schema.MapAttribute{ Description: "Mapping of MAC addresses to IP addresses", Computed: true, diff --git a/internal/services/magic_transit_site_lan/list_data_source_model.go b/internal/services/magic_transit_site_lan/list_data_source_model.go index d28ad3ec73..d1180ce06e 100644 --- a/internal/services/magic_transit_site_lan/list_data_source_model.go +++ b/internal/services/magic_transit_site_lan/list_data_source_model.go @@ -70,8 +70,9 @@ type MagicTransitSiteLANsStaticAddressingDHCPRelayDataSourceModel struct { } type MagicTransitSiteLANsStaticAddressingDHCPServerDataSourceModel struct { - DHCPPoolEnd types.String `tfsdk:"dhcp_pool_end" json:"dhcp_pool_end,computed"` - DHCPPoolStart types.String `tfsdk:"dhcp_pool_start" json:"dhcp_pool_start,computed"` - DNSServer types.String `tfsdk:"dns_server" json:"dns_server,computed"` - Reservations customfield.Map[types.String] `tfsdk:"reservations" json:"reservations,computed"` + DHCPPoolEnd types.String `tfsdk:"dhcp_pool_end" json:"dhcp_pool_end,computed"` + DHCPPoolStart types.String `tfsdk:"dhcp_pool_start" json:"dhcp_pool_start,computed"` + DNSServer types.String `tfsdk:"dns_server" json:"dns_server,computed"` + DNSServers customfield.List[types.String] `tfsdk:"dns_servers" json:"dns_servers,computed"` + Reservations customfield.Map[types.String] `tfsdk:"reservations" json:"reservations,computed"` } diff --git a/internal/services/magic_transit_site_lan/list_data_source_schema.go b/internal/services/magic_transit_site_lan/list_data_source_schema.go index 84ba1d3ba9..731ef79b96 100644 --- a/internal/services/magic_transit_site_lan/list_data_source_schema.go +++ b/internal/services/magic_transit_site_lan/list_data_source_schema.go @@ -130,6 +130,11 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "A valid IPv4 address.", Computed: true, }, + "dns_servers": schema.ListAttribute{ + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, "reservations": schema.MapAttribute{ Description: "Mapping of MAC addresses to IP addresses", Computed: true, diff --git a/internal/services/magic_transit_site_lan/model.go b/internal/services/magic_transit_site_lan/model.go index 1d0a9446d3..07d3b5cf3c 100644 --- a/internal/services/magic_transit_site_lan/model.go +++ b/internal/services/magic_transit_site_lan/model.go @@ -13,9 +13,9 @@ type MagicTransitSiteLANResultEnvelope struct { } type MagicTransitSiteLANModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` SiteID types.String `tfsdk:"site_id" path:"site_id,required"` - LANID types.String `tfsdk:"lan_id" path:"lan_id,optional"` HaLink types.Bool `tfsdk:"ha_link" json:"ha_link,optional"` Physport types.Int64 `tfsdk:"physport" json:"physport,required"` VlanTag types.Int64 `tfsdk:"vlan_tag" json:"vlan_tag,required"` @@ -23,7 +23,6 @@ type MagicTransitSiteLANModel struct { Nat customfield.NestedObject[MagicTransitSiteLANNatModel] `tfsdk:"nat" json:"nat,computed_optional"` RoutedSubnets customfield.NestedObjectList[MagicTransitSiteLANRoutedSubnetsModel] `tfsdk:"routed_subnets" json:"routed_subnets,computed_optional"` StaticAddressing customfield.NestedObject[MagicTransitSiteLANStaticAddressingModel] `tfsdk:"static_addressing" json:"static_addressing,computed_optional"` - ID types.String `tfsdk:"id" json:"id,computed"` } func (m MagicTransitSiteLANModel) MarshalJSON() (data []byte, err error) { @@ -64,5 +63,6 @@ type MagicTransitSiteLANStaticAddressingDHCPServerModel struct { DHCPPoolEnd types.String `tfsdk:"dhcp_pool_end" json:"dhcp_pool_end,optional"` DHCPPoolStart types.String `tfsdk:"dhcp_pool_start" json:"dhcp_pool_start,optional"` DNSServer types.String `tfsdk:"dns_server" json:"dns_server,optional"` + DNSServers *[]types.String `tfsdk:"dns_servers" json:"dns_servers,optional"` Reservations *map[string]types.String `tfsdk:"reservations" json:"reservations,optional"` } diff --git a/internal/services/magic_transit_site_lan/resource.go b/internal/services/magic_transit_site_lan/resource.go index 01dc5cab7c..22ffa9409b 100644 --- a/internal/services/magic_transit_site_lan/resource.go +++ b/internal/services/magic_transit_site_lan/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/magic_transit" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*MagicTransitSiteLANResource)(nil) var _ resource.ResourceWithModifyPlan = (*MagicTransitSiteLANResource)(nil) +var _ resource.ResourceWithImportState = (*MagicTransitSiteLANResource)(nil) func NewResource() resource.Resource { return &MagicTransitSiteLANResource{} @@ -120,7 +123,7 @@ func (r *MagicTransitSiteLANResource) Update(ctx context.Context, req resource.U _, err = r.client.MagicTransit.Sites.LANs.Update( ctx, data.SiteID.ValueString(), - data.LANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteLANUpdateParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -157,7 +160,7 @@ func (r *MagicTransitSiteLANResource) Read(ctx context.Context, req resource.Rea _, err := r.client.MagicTransit.Sites.LANs.Get( ctx, data.SiteID.ValueString(), - data.LANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteLANGetParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -196,7 +199,7 @@ func (r *MagicTransitSiteLANResource) Delete(ctx context.Context, req resource.D _, err := r.client.MagicTransit.Sites.LANs.Delete( ctx, data.SiteID.ValueString(), - data.LANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteLANDeleteParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -210,6 +213,55 @@ func (r *MagicTransitSiteLANResource) Delete(ctx context.Context, req resource.D resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *MagicTransitSiteLANResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *MagicTransitSiteLANModel = new(MagicTransitSiteLANModel) + + path_account_id := "" + path_site_id := "" + path_lan_id := "" + diags := importpath.ParseImportID( + req.ID, + "//", + &path_account_id, + &path_site_id, + &path_lan_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountID = types.StringValue(path_account_id) + data.SiteID = types.StringValue(path_site_id) + data.ID = types.StringValue(path_lan_id) + + res := new(http.Response) + env := MagicTransitSiteLANResultEnvelope{*data} + _, err := r.client.MagicTransit.Sites.LANs.Get( + ctx, + path_site_id, + path_lan_id, + magic_transit.SiteLANGetParams{ + AccountID: cloudflare.F(path_account_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *MagicTransitSiteLANResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/magic_transit_site_lan/schema.go b/internal/services/magic_transit_site_lan/schema.go index 61cd7f35ba..d17d604488 100644 --- a/internal/services/magic_transit_site_lan/schema.go +++ b/internal/services/magic_transit_site_lan/schema.go @@ -19,6 +19,11 @@ var _ resource.ResourceWithConfigValidators = (*MagicTransitSiteLANResource)(nil func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, "account_id": schema.StringAttribute{ Description: "Identifier", Required: true, @@ -29,11 +34,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "lan_id": schema.StringAttribute{ - Description: "Identifier", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "ha_link": schema.BoolAttribute{ Description: "mark true to use this LAN for HA probing. only works for site with HA turned on. only one LAN can be set as the ha_link.", Optional: true, @@ -127,6 +127,10 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "A valid IPv4 address.", Optional: true, }, + "dns_servers": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + }, "reservations": schema.MapAttribute{ Description: "Mapping of MAC addresses to IP addresses", Optional: true, @@ -144,10 +148,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "id": schema.StringAttribute{ - Description: "Identifier", - Computed: true, - }, }, } } diff --git a/internal/services/magic_transit_site_wan/data_source_model.go b/internal/services/magic_transit_site_wan/data_source_model.go index 6bab05937e..3ea0e3c605 100644 --- a/internal/services/magic_transit_site_wan/data_source_model.go +++ b/internal/services/magic_transit_site_wan/data_source_model.go @@ -17,11 +17,11 @@ type MagicTransitSiteWANResultDataSourceEnvelope struct { } type MagicTransitSiteWANDataSourceModel struct { + ID types.String `tfsdk:"id" json:"-,computed"` + WANID types.String `tfsdk:"wan_id" path:"wan_id,optional"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - WANID types.String `tfsdk:"wan_id" path:"wan_id,required"` SiteID types.String `tfsdk:"site_id" path:"site_id,computed"` HealthCheckRate types.String `tfsdk:"health_check_rate" json:"health_check_rate,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` Name types.String `tfsdk:"name" json:"name,computed"` Physport types.Int64 `tfsdk:"physport" json:"physport,computed"` Priority types.Int64 `tfsdk:"priority" json:"priority,computed"` @@ -37,6 +37,14 @@ func (m *MagicTransitSiteWANDataSourceModel) toReadParams(_ context.Context) (pa return } +func (m *MagicTransitSiteWANDataSourceModel) toListParams(_ context.Context) (params magic_transit.SiteWANListParams, diags diag.Diagnostics) { + params = magic_transit.SiteWANListParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + type MagicTransitSiteWANStaticAddressingDataSourceModel struct { Address types.String `tfsdk:"address" json:"address,computed"` GatewayAddress types.String `tfsdk:"gateway_address" json:"gateway_address,computed"` diff --git a/internal/services/magic_transit_site_wan/data_source_schema.go b/internal/services/magic_transit_site_wan/data_source_schema.go index eb76aaba76..69c4745869 100644 --- a/internal/services/magic_transit_site_wan/data_source_schema.go +++ b/internal/services/magic_transit_site_wan/data_source_schema.go @@ -17,11 +17,15 @@ var _ datasource.DataSourceWithConfigValidators = (*MagicTransitSiteWANDataSourc func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ - "account_id": schema.StringAttribute{ + "id": schema.StringAttribute{ Description: "Identifier", - Required: true, + Computed: true, }, "wan_id": schema.StringAttribute{ + Description: "Identifier", + Optional: true, + }, + "account_id": schema.StringAttribute{ Description: "Identifier", Required: true, }, @@ -40,10 +44,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { ), }, }, - "id": schema.StringAttribute{ - Description: "Identifier", - Computed: true, - }, "name": schema.StringAttribute{ Computed: true, }, diff --git a/internal/services/magic_transit_site_wan/model.go b/internal/services/magic_transit_site_wan/model.go index df3684e754..506e0b7e78 100644 --- a/internal/services/magic_transit_site_wan/model.go +++ b/internal/services/magic_transit_site_wan/model.go @@ -13,16 +13,15 @@ type MagicTransitSiteWANResultEnvelope struct { } type MagicTransitSiteWANModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` SiteID types.String `tfsdk:"site_id" path:"site_id,required"` - WANID types.String `tfsdk:"wan_id" path:"wan_id,optional"` Physport types.Int64 `tfsdk:"physport" json:"physport,required"` VlanTag types.Int64 `tfsdk:"vlan_tag" json:"vlan_tag,required"` Name types.String `tfsdk:"name" json:"name,optional"` Priority types.Int64 `tfsdk:"priority" json:"priority,optional"` StaticAddressing customfield.NestedObject[MagicTransitSiteWANStaticAddressingModel] `tfsdk:"static_addressing" json:"static_addressing,computed_optional"` HealthCheckRate types.String `tfsdk:"health_check_rate" json:"health_check_rate,computed"` - ID types.String `tfsdk:"id" json:"id,computed"` } func (m MagicTransitSiteWANModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/magic_transit_site_wan/resource.go b/internal/services/magic_transit_site_wan/resource.go index e81ee1fc1a..f32834bfeb 100644 --- a/internal/services/magic_transit_site_wan/resource.go +++ b/internal/services/magic_transit_site_wan/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/magic_transit" "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*MagicTransitSiteWANResource)(nil) var _ resource.ResourceWithModifyPlan = (*MagicTransitSiteWANResource)(nil) +var _ resource.ResourceWithImportState = (*MagicTransitSiteWANResource)(nil) func NewResource() resource.Resource { return &MagicTransitSiteWANResource{} @@ -120,7 +123,7 @@ func (r *MagicTransitSiteWANResource) Update(ctx context.Context, req resource.U _, err = r.client.MagicTransit.Sites.WANs.Update( ctx, data.SiteID.ValueString(), - data.WANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteWANUpdateParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -157,7 +160,7 @@ func (r *MagicTransitSiteWANResource) Read(ctx context.Context, req resource.Rea _, err := r.client.MagicTransit.Sites.WANs.Get( ctx, data.SiteID.ValueString(), - data.WANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteWANGetParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -196,7 +199,7 @@ func (r *MagicTransitSiteWANResource) Delete(ctx context.Context, req resource.D _, err := r.client.MagicTransit.Sites.WANs.Delete( ctx, data.SiteID.ValueString(), - data.WANID.ValueString(), + data.ID.ValueString(), magic_transit.SiteWANDeleteParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -210,6 +213,55 @@ func (r *MagicTransitSiteWANResource) Delete(ctx context.Context, req resource.D resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *MagicTransitSiteWANResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *MagicTransitSiteWANModel = new(MagicTransitSiteWANModel) + + path_account_id := "" + path_site_id := "" + path_wan_id := "" + diags := importpath.ParseImportID( + req.ID, + "//", + &path_account_id, + &path_site_id, + &path_wan_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountID = types.StringValue(path_account_id) + data.SiteID = types.StringValue(path_site_id) + data.ID = types.StringValue(path_wan_id) + + res := new(http.Response) + env := MagicTransitSiteWANResultEnvelope{*data} + _, err := r.client.MagicTransit.Sites.WANs.Get( + ctx, + path_site_id, + path_wan_id, + magic_transit.SiteWANGetParams{ + AccountID: cloudflare.F(path_account_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *MagicTransitSiteWANResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/magic_transit_site_wan/schema.go b/internal/services/magic_transit_site_wan/schema.go index e9b25a0b16..698e670165 100644 --- a/internal/services/magic_transit_site_wan/schema.go +++ b/internal/services/magic_transit_site_wan/schema.go @@ -20,6 +20,11 @@ var _ resource.ResourceWithConfigValidators = (*MagicTransitSiteWANResource)(nil func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, "account_id": schema.StringAttribute{ Description: "Identifier", Required: true, @@ -30,11 +35,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "wan_id": schema.StringAttribute{ - Description: "Identifier", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "physport": schema.Int64Attribute{ Required: true, }, @@ -80,10 +80,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, Default: stringdefault.StaticString("mid"), }, - "id": schema.StringAttribute{ - Description: "Identifier", - Computed: true, - }, }, } } diff --git a/internal/services/magic_wan_gre_tunnel/resource_test.go b/internal/services/magic_wan_gre_tunnel/resource_test.go index 7288680954..f1288392e3 100644 --- a/internal/services/magic_wan_gre_tunnel/resource_test.go +++ b/internal/services/magic_wan_gre_tunnel/resource_test.go @@ -1,4 +1,4 @@ -package magic_wan_gre_tunnel +package magic_wan_gre_tunnel_test import ( "context" diff --git a/internal/services/magic_wan_static_route/model.go b/internal/services/magic_wan_static_route/model.go index 6a4d95d950..6c858dd5b1 100644 --- a/internal/services/magic_wan_static_route/model.go +++ b/internal/services/magic_wan_static_route/model.go @@ -24,8 +24,8 @@ type MagicWANStaticRouteModel struct { Scope customfield.NestedObject[MagicWANStaticRouteScopeModel] `tfsdk:"scope" json:"scope,computed_optional"` Modified types.Bool `tfsdk:"modified" json:"modified,computed"` ModifiedRoute customfield.NestedObject[MagicWANStaticRouteModifiedRouteModel] `tfsdk:"modified_route" json:"modified_route,computed"` - Route customfield.NestedObject[MagicWANStaticRouteRouteModel] `tfsdk:"route" json:"route,computed"` - Routes customfield.NestedObjectList[MagicWANStaticRouteRoutesModel] `tfsdk:"routes" json:"routes,computed"` + Route customfield.NestedObject[MagicWANStaticRouteRouteModel] `tfsdk:"route" json:"route,computed_optional"` + Routes customfield.NestedObjectList[MagicWANStaticRouteRoutesModel] `tfsdk:"routes" json:"routes,computed_optional"` } func (m MagicWANStaticRouteModel) MarshalJSON() (data []byte, err error) { @@ -59,35 +59,35 @@ type MagicWANStaticRouteModifiedRouteScopeModel struct { } type MagicWANStaticRouteRouteModel struct { - Nexthop types.String `tfsdk:"nexthop" json:"nexthop,computed"` - Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` - Priority types.Int64 `tfsdk:"priority" json:"priority,computed"` + Nexthop types.String `tfsdk:"nexthop" json:"nexthop,computed_optional"` + Prefix types.String `tfsdk:"prefix" json:"prefix,computed_optional"` + Priority types.Int64 `tfsdk:"priority" json:"priority,computed_optional"` ID types.String `tfsdk:"id" json:"id,computed"` CreatedOn timetypes.RFC3339 `tfsdk:"created_on" json:"created_on,computed" format:"date-time"` - Description types.String `tfsdk:"description" json:"description,computed"` + Description types.String `tfsdk:"description" json:"description,computed_optional"` ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` - Scope customfield.NestedObject[MagicWANStaticRouteRouteScopeModel] `tfsdk:"scope" json:"scope,computed"` - Weight types.Int64 `tfsdk:"weight" json:"weight,computed"` + Scope customfield.NestedObject[MagicWANStaticRouteRouteScopeModel] `tfsdk:"scope" json:"scope,computed_optional"` + Weight types.Int64 `tfsdk:"weight" json:"weight,computed_optional"` } type MagicWANStaticRouteRouteScopeModel struct { - ColoNames customfield.List[types.String] `tfsdk:"colo_names" json:"colo_names,computed"` - ColoRegions customfield.List[types.String] `tfsdk:"colo_regions" json:"colo_regions,computed"` + ColoNames customfield.List[types.String] `tfsdk:"colo_names" json:"colo_names,computed_optional"` + ColoRegions customfield.List[types.String] `tfsdk:"colo_regions" json:"colo_regions,computed_optional"` } type MagicWANStaticRouteRoutesModel struct { - Nexthop types.String `tfsdk:"nexthop" json:"nexthop,computed"` - Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` - Priority types.Int64 `tfsdk:"priority" json:"priority,computed"` + Nexthop types.String `tfsdk:"nexthop" json:"nexthop,computed_optional"` + Prefix types.String `tfsdk:"prefix" json:"prefix,computed_optional"` + Priority types.Int64 `tfsdk:"priority" json:"priority,computed_optional"` ID types.String `tfsdk:"id" json:"id,computed"` CreatedOn timetypes.RFC3339 `tfsdk:"created_on" json:"created_on,computed" format:"date-time"` - Description types.String `tfsdk:"description" json:"description,computed"` + Description types.String `tfsdk:"description" json:"description,computed_optional"` ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` - Scope customfield.NestedObject[MagicWANStaticRouteRoutesScopeModel] `tfsdk:"scope" json:"scope,computed"` - Weight types.Int64 `tfsdk:"weight" json:"weight,computed"` + Scope customfield.NestedObject[MagicWANStaticRouteRoutesScopeModel] `tfsdk:"scope" json:"scope,computed_optional"` + Weight types.Int64 `tfsdk:"weight" json:"weight,computed_optional"` } type MagicWANStaticRouteRoutesScopeModel struct { - ColoNames customfield.List[types.String] `tfsdk:"colo_names" json:"colo_names,computed"` - ColoRegions customfield.List[types.String] `tfsdk:"colo_regions" json:"colo_regions,computed"` + ColoNames customfield.List[types.String] `tfsdk:"colo_names" json:"colo_names,computed_optional"` + ColoRegions customfield.List[types.String] `tfsdk:"colo_regions" json:"colo_regions,computed_optional"` } diff --git a/internal/services/magic_wan_static_route/resource.go b/internal/services/magic_wan_static_route/resource.go index 35b8a0e0ae..65cdfd7fb7 100644 --- a/internal/services/magic_wan_static_route/resource.go +++ b/internal/services/magic_wan_static_route/resource.go @@ -62,6 +62,11 @@ func (r *MagicWANStaticRouteResource) Create(ctx context.Context, req resource.C } dataBytes, err := data.MarshalJSON() + + // Workaround to wrap the route into an array, which is what the API expects. + dataBytes = append([]byte("["), dataBytes...) + dataBytes = append(dataBytes, byte(']')) + if err != nil { resp.Diagnostics.AddError("failed to serialize http request", err.Error()) return diff --git a/internal/services/magic_wan_static_route/schema.go b/internal/services/magic_wan_static_route/schema.go index 2858c6b0fe..f860eb7606 100644 --- a/internal/services/magic_wan_static_route/schema.go +++ b/internal/services/magic_wan_static_route/schema.go @@ -131,19 +131,23 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "route": schema.SingleNestedAttribute{ Computed: true, + Optional: true, CustomType: customfield.NewNestedObjectType[MagicWANStaticRouteRouteModel](ctx), Attributes: map[string]schema.Attribute{ "nexthop": schema.StringAttribute{ Description: "The next-hop IP Address for the static route.", Computed: true, + Optional: true, }, "prefix": schema.StringAttribute{ Description: "IP Prefix in Classless Inter-Domain Routing format.", Computed: true, + Optional: true, }, "priority": schema.Int64Attribute{ Description: "Priority of the static route.", Computed: true, + Optional: true, }, "id": schema.StringAttribute{ Description: "Identifier", @@ -157,6 +161,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "description": schema.StringAttribute{ Description: "An optional human provided description of the static route.", Computed: true, + Optional: true, }, "modified_on": schema.StringAttribute{ Description: "When the route was last modified.", @@ -166,17 +171,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { "scope": schema.SingleNestedAttribute{ Description: "Used only for ECMP routes.", Computed: true, + Optional: true, CustomType: customfield.NewNestedObjectType[MagicWANStaticRouteRouteScopeModel](ctx), Attributes: map[string]schema.Attribute{ "colo_names": schema.ListAttribute{ Description: "List of colo names for the ECMP scope.", Computed: true, + Optional: true, CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, "colo_regions": schema.ListAttribute{ Description: "List of colo regions for the ECMP scope.", Computed: true, + Optional: true, CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, @@ -185,25 +193,30 @@ func ResourceSchema(ctx context.Context) schema.Schema { "weight": schema.Int64Attribute{ Description: "Optional weight of the ECMP scope - if provided.", Computed: true, + Optional: true, }, }, }, "routes": schema.ListNestedAttribute{ Computed: true, + Optional: true, CustomType: customfield.NewNestedObjectListType[MagicWANStaticRouteRoutesModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "nexthop": schema.StringAttribute{ Description: "The next-hop IP Address for the static route.", Computed: true, + Optional: true, }, "prefix": schema.StringAttribute{ Description: "IP Prefix in Classless Inter-Domain Routing format.", Computed: true, + Optional: true, }, "priority": schema.Int64Attribute{ Description: "Priority of the static route.", Computed: true, + Optional: true, }, "id": schema.StringAttribute{ Description: "Identifier", @@ -217,6 +230,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "description": schema.StringAttribute{ Description: "An optional human provided description of the static route.", Computed: true, + Optional: true, }, "modified_on": schema.StringAttribute{ Description: "When the route was last modified.", @@ -226,17 +240,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { "scope": schema.SingleNestedAttribute{ Description: "Used only for ECMP routes.", Computed: true, + Optional: true, CustomType: customfield.NewNestedObjectType[MagicWANStaticRouteRoutesScopeModel](ctx), Attributes: map[string]schema.Attribute{ "colo_names": schema.ListAttribute{ Description: "List of colo names for the ECMP scope.", Computed: true, + Optional: true, CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, "colo_regions": schema.ListAttribute{ Description: "List of colo regions for the ECMP scope.", Computed: true, + Optional: true, CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, @@ -245,6 +262,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "weight": schema.Int64Attribute{ Description: "Optional weight of the ECMP scope - if provided.", Computed: true, + Optional: true, }, }, }, diff --git a/internal/services/mtls_certificate/data_source_model.go b/internal/services/mtls_certificate/data_source_model.go index aee52af4f2..abc8177a3a 100644 --- a/internal/services/mtls_certificate/data_source_model.go +++ b/internal/services/mtls_certificate/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/mtls_certificates" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type MTLSCertificateResultDataSourceEnvelope struct { Result MTLSCertificateDataSourceModel `json:"result,computed"` } -type MTLSCertificateResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[MTLSCertificateDataSourceModel] `json:"result,computed"` -} - type MTLSCertificateDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` MTLSCertificateID types.String `tfsdk:"mtls_certificate_id" path:"mtls_certificate_id,optional"` diff --git a/internal/services/notification_policy/data_source_model.go b/internal/services/notification_policy/data_source_model.go index cb23991397..08af7ff1c4 100644 --- a/internal/services/notification_policy/data_source_model.go +++ b/internal/services/notification_policy/data_source_model.go @@ -17,10 +17,6 @@ type NotificationPolicyResultDataSourceEnvelope struct { Result NotificationPolicyDataSourceModel `json:"result,computed"` } -type NotificationPolicyResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[NotificationPolicyDataSourceModel] `json:"result,computed"` -} - type NotificationPolicyDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PolicyID types.String `tfsdk:"policy_id" path:"policy_id,optional"` diff --git a/internal/services/notification_policy_webhooks/data_source_model.go b/internal/services/notification_policy_webhooks/data_source_model.go index b13d1985c3..a047b07d71 100644 --- a/internal/services/notification_policy_webhooks/data_source_model.go +++ b/internal/services/notification_policy_webhooks/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/alerting" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type NotificationPolicyWebhooksResultDataSourceEnvelope struct { Result NotificationPolicyWebhooksDataSourceModel `json:"result,computed"` } -type NotificationPolicyWebhooksResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[NotificationPolicyWebhooksDataSourceModel] `json:"result,computed"` -} - type NotificationPolicyWebhooksDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` WebhookID types.String `tfsdk:"webhook_id" path:"webhook_id,optional"` diff --git a/internal/services/origin_ca_certificate/data_source.go b/internal/services/origin_ca_certificate/data_source.go index c67d151e04..d899a2e6db 100644 --- a/internal/services/origin_ca_certificate/data_source.go +++ b/internal/services/origin_ca_certificate/data_source.go @@ -64,7 +64,7 @@ func (d *OriginCACertificateDataSource) Read(ctx context.Context, req datasource return } - env := OriginCACertificateResultListDataSourceEnvelope{} + env := OriginCACertificatesResultListDataSourceEnvelope{} page, err := d.client.OriginCACertificates.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *OriginCACertificateDataSource) Read(ctx context.Context, req datasource } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.CertificateID = ts[0].CertificateID + data.CertificateID = ts[0].ID } res := new(http.Response) diff --git a/internal/services/origin_ca_certificate/data_source_model.go b/internal/services/origin_ca_certificate/data_source_model.go index cd94194ce9..6c4e49c2b8 100644 --- a/internal/services/origin_ca_certificate/data_source_model.go +++ b/internal/services/origin_ca_certificate/data_source_model.go @@ -16,10 +16,6 @@ type OriginCACertificateResultDataSourceEnvelope struct { Result OriginCACertificateDataSourceModel `json:"result,computed"` } -type OriginCACertificateResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[OriginCACertificateDataSourceModel] `json:"result,computed"` -} - type OriginCACertificateDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CertificateID types.String `tfsdk:"certificate_id" path:"certificate_id,optional"` diff --git a/internal/services/page_rule/custom.go b/internal/services/page_rule/custom.go index fd28df1f0b..0fc1dd52dc 100644 --- a/internal/services/page_rule/custom.go +++ b/internal/services/page_rule/custom.go @@ -67,14 +67,14 @@ func (m PageRuleModel) marshalTargetsAndActions(b []byte) (data []byte, err erro } type PageRuleActionsCacheKeyFieldsQueryStringModel struct { - Include []types.String `tfsdk:"include" json:"include,optional,omitempty"` - Exclude []types.String `tfsdk:"exclude" json:"exclude,optional,omitempty"` + Include []types.String `tfsdk:"include" json:"include,computed_optional,omitempty"` + Exclude []types.String `tfsdk:"exclude" json:"exclude,computed_optional,omitempty"` } type PageRuleActionsCacheKeyFieldsHeaderModel struct { - CheckPresence []types.String `tfsdk:"check_presence" json:"check_presence,optional,omitempty"` - Include []types.String `tfsdk:"include" json:"include,optional,omitempty"` - Exclude []types.String `tfsdk:"exclude" json:"exclude,optional,omitempty"` + CheckPresence []types.String `tfsdk:"check_presence" json:"check_presence,computed_optional,omitempty"` + Include []types.String `tfsdk:"include" json:"include,computed_optional,omitempty"` + Exclude []types.String `tfsdk:"exclude" json:"exclude,computed_optional,omitempty"` } type PageRuleActionsCacheKeyFieldsHostModel struct { @@ -82,8 +82,8 @@ type PageRuleActionsCacheKeyFieldsHostModel struct { } type PageRuleActionsCacheKeyFieldsCookieModel struct { - Include []types.String `tfsdk:"include" json:"include,optional,omitempty"` - CheckPresence []types.String `tfsdk:"check_presence" json:"check_presence,optional,omitempty"` + Include []types.String `tfsdk:"include" json:"include,computed_optional,omitempty"` + CheckPresence []types.String `tfsdk:"check_presence" json:"check_presence,computed_optional,omitempty"` } type PageRuleActionsCacheKeyFieldsUserModel struct { diff --git a/internal/services/page_shield_policy/data_source_model.go b/internal/services/page_shield_policy/data_source_model.go index c667ccf61c..a5397d330b 100644 --- a/internal/services/page_shield_policy/data_source_model.go +++ b/internal/services/page_shield_policy/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/page_shield" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type PageShieldPolicyResultDataSourceEnvelope struct { Result PageShieldPolicyDataSourceModel `json:"result,computed"` } -type PageShieldPolicyResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[PageShieldPolicyDataSourceModel] `json:"result,computed"` -} - type PageShieldPolicyDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PolicyID types.String `tfsdk:"policy_id" path:"policy_id,optional"` diff --git a/internal/services/pages_domain/data_source_model.go b/internal/services/pages_domain/data_source_model.go index a4c8134302..ed96475cba 100644 --- a/internal/services/pages_domain/data_source_model.go +++ b/internal/services/pages_domain/data_source_model.go @@ -16,10 +16,6 @@ type PagesDomainResultDataSourceEnvelope struct { Result PagesDomainDataSourceModel `json:"result,computed"` } -type PagesDomainResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[PagesDomainDataSourceModel] `json:"result,computed"` -} - type PagesDomainDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DomainName types.String `tfsdk:"domain_name" path:"domain_name,optional"` diff --git a/internal/services/pages_domain/model.go b/internal/services/pages_domain/model.go index 3674a12e9a..d70213dcac 100644 --- a/internal/services/pages_domain/model.go +++ b/internal/services/pages_domain/model.go @@ -13,10 +13,10 @@ type PagesDomainResultEnvelope struct { } type PagesDomainModel struct { - ID types.String `tfsdk:"id" json:"id,computed"` + ID types.String `tfsdk:"id" json:"-,computed"` + Name types.String `tfsdk:"name" json:"name,required"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` ProjectName types.String `tfsdk:"project_name" path:"project_name,required"` - Name types.String `tfsdk:"name" json:"name,optional"` CertificateAuthority types.String `tfsdk:"certificate_authority" json:"certificate_authority,computed"` CreatedOn types.String `tfsdk:"created_on" json:"created_on,computed"` DomainID types.String `tfsdk:"domain_id" json:"domain_id,computed"` diff --git a/internal/services/pages_domain/resource.go b/internal/services/pages_domain/resource.go index 4b21ee95cd..42fca0cd7e 100644 --- a/internal/services/pages_domain/resource.go +++ b/internal/services/pages_domain/resource.go @@ -92,6 +92,7 @@ func (r *PagesDomainResource) Create(ctx context.Context, req resource.CreateReq return } data = &env.Result + data.ID = data.Name resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -123,7 +124,7 @@ func (r *PagesDomainResource) Update(ctx context.Context, req resource.UpdateReq _, err = r.client.Pages.Projects.Domains.Edit( ctx, data.ProjectName.ValueString(), - data.ID.ValueString(), + data.Name.ValueString(), pages.ProjectDomainEditParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -142,6 +143,7 @@ func (r *PagesDomainResource) Update(ctx context.Context, req resource.UpdateReq return } data = &env.Result + data.ID = data.Name resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -160,7 +162,7 @@ func (r *PagesDomainResource) Read(ctx context.Context, req resource.ReadRequest _, err := r.client.Pages.Projects.Domains.Get( ctx, data.ProjectName.ValueString(), - data.ID.ValueString(), + data.Name.ValueString(), pages.ProjectDomainGetParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -183,6 +185,7 @@ func (r *PagesDomainResource) Read(ctx context.Context, req resource.ReadRequest return } data = &env.Result + data.ID = data.Name resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -199,7 +202,7 @@ func (r *PagesDomainResource) Delete(ctx context.Context, req resource.DeleteReq _, err := r.client.Pages.Projects.Domains.Delete( ctx, data.ProjectName.ValueString(), - data.ID.ValueString(), + data.Name.ValueString(), pages.ProjectDomainDeleteParams{ AccountID: cloudflare.F(data.AccountID.ValueString()), }, @@ -209,6 +212,7 @@ func (r *PagesDomainResource) Delete(ctx context.Context, req resource.DeleteReq resp.Diagnostics.AddError("failed to make http request", err.Error()) return } + data.ID = data.Name resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -233,7 +237,7 @@ func (r *PagesDomainResource) ImportState(ctx context.Context, req resource.Impo data.AccountID = types.StringValue(path_account_id) data.ProjectName = types.StringValue(path_project_name) - data.ID = types.StringValue(path_domain_name) + data.Name = types.StringValue(path_domain_name) res := new(http.Response) env := PagesDomainResultEnvelope{*data} @@ -258,6 +262,7 @@ func (r *PagesDomainResource) ImportState(ctx context.Context, req resource.Impo return } data = &env.Result + data.ID = data.Name resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/services/pages_domain/schema.go b/internal/services/pages_domain/schema.go index d44f8df01e..2fdf7bde43 100644 --- a/internal/services/pages_domain/schema.go +++ b/internal/services/pages_domain/schema.go @@ -21,7 +21,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "account_id": schema.StringAttribute{ Description: "Identifier", @@ -33,10 +37,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "name": schema.StringAttribute{ - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "certificate_authority": schema.StringAttribute{ Computed: true, Validators: []validator.String{ diff --git a/internal/services/permission_group/list_data_source_model.go b/internal/services/permission_group/list_data_source_model.go index f0d72ac51c..fa79788cd7 100644 --- a/internal/services/permission_group/list_data_source_model.go +++ b/internal/services/permission_group/list_data_source_model.go @@ -44,4 +44,12 @@ func (m *PermissionGroupsDataSourceModel) toListParams(_ context.Context) (param } type PermissionGroupsResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Meta customfield.NestedObject[PermissionGroupsMetaDataSourceModel] `tfsdk:"meta" json:"meta,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` +} + +type PermissionGroupsMetaDataSourceModel struct { + Key types.String `tfsdk:"key" json:"key,computed"` + Value types.String `tfsdk:"value" json:"value,computed"` } diff --git a/internal/services/permission_group/list_data_source_schema.go b/internal/services/permission_group/list_data_source_schema.go index 301b9a210b..b49280cbac 100644 --- a/internal/services/permission_group/list_data_source_schema.go +++ b/internal/services/permission_group/list_data_source_schema.go @@ -45,7 +45,29 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectListType[PermissionGroupsResultDataSourceModel](ctx), NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{}, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier of the group.", + Computed: true, + }, + "meta": schema.SingleNestedAttribute{ + Description: "Attributes associated to the permission group.", + Computed: true, + CustomType: customfield.NewNestedObjectType[PermissionGroupsMetaDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Computed: true, + }, + "value": schema.StringAttribute{ + Computed: true, + }, + }, + }, + "name": schema.StringAttribute{ + Description: "Name of the group.", + Computed: true, + }, + }, }, }, }, diff --git a/internal/services/queue/data_source_model.go b/internal/services/queue/data_source_model.go index 52e61c672b..11ed1f8b18 100644 --- a/internal/services/queue/data_source_model.go +++ b/internal/services/queue/data_source_model.go @@ -16,10 +16,6 @@ type QueueResultDataSourceEnvelope struct { Result QueueDataSourceModel `json:"result,computed"` } -type QueueResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[QueueDataSourceModel] `json:"result,computed"` -} - type QueueDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` QueueID types.String `tfsdk:"queue_id" path:"queue_id,computed_optional"` diff --git a/internal/services/queue_consumer/data_source_model.go b/internal/services/queue_consumer/data_source_model.go index d6a5ac2c94..6ada68c19c 100644 --- a/internal/services/queue_consumer/data_source_model.go +++ b/internal/services/queue_consumer/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/queues" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +17,14 @@ type QueueConsumerResultDataSourceEnvelope struct { } type QueueConsumerDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - QueueID types.String `tfsdk:"queue_id" path:"queue_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + QueueID types.String `tfsdk:"queue_id" path:"queue_id,computed"` + ConsumerID types.String `tfsdk:"consumer_id" json:"consumer_id,computed"` + CreatedOn types.String `tfsdk:"created_on" json:"created_on,computed"` + Script types.String `tfsdk:"script" json:"script,computed"` + ScriptName types.String `tfsdk:"script_name" json:"script_name,computed"` + Type types.String `tfsdk:"type" json:"type,computed"` + Settings customfield.NestedObject[QueueConsumerSettingsDataSourceModel] `tfsdk:"settings" json:"settings,computed"` } func (m *QueueConsumerDataSourceModel) toReadParams(_ context.Context) (params queues.ConsumerGetParams, diags diag.Diagnostics) { @@ -27,3 +34,12 @@ func (m *QueueConsumerDataSourceModel) toReadParams(_ context.Context) (params q return } + +type QueueConsumerSettingsDataSourceModel struct { + BatchSize types.Float64 `tfsdk:"batch_size" json:"batch_size,computed"` + MaxConcurrency types.Float64 `tfsdk:"max_concurrency" json:"max_concurrency,computed"` + MaxRetries types.Float64 `tfsdk:"max_retries" json:"max_retries,computed"` + MaxWaitTimeMs types.Float64 `tfsdk:"max_wait_time_ms" json:"max_wait_time_ms,computed"` + RetryDelay types.Float64 `tfsdk:"retry_delay" json:"retry_delay,computed"` + VisibilityTimeoutMs types.Float64 `tfsdk:"visibility_timeout_ms" json:"visibility_timeout_ms,computed"` +} diff --git a/internal/services/queue_consumer/data_source_schema.go b/internal/services/queue_consumer/data_source_schema.go index dbfc8a45b4..d5656504eb 100644 --- a/internal/services/queue_consumer/data_source_schema.go +++ b/internal/services/queue_consumer/data_source_schema.go @@ -5,8 +5,11 @@ package queue_consumer import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) var _ datasource.DataSourceWithConfigValidators = (*QueueConsumerDataSource)(nil) @@ -20,7 +23,58 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, "queue_id": schema.StringAttribute{ Description: "A Resource identifier.", - Required: true, + Computed: true, + }, + "consumer_id": schema.StringAttribute{ + Description: "A Resource identifier.", + Computed: true, + }, + "created_on": schema.StringAttribute{ + Computed: true, + }, + "script": schema.StringAttribute{ + Description: "Name of a Worker", + Computed: true, + }, + "script_name": schema.StringAttribute{ + Description: "Name of a Worker", + Computed: true, + }, + "type": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("worker", "http_pull"), + }, + }, + "settings": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[QueueConsumerSettingsDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "batch_size": schema.Float64Attribute{ + Description: "The maximum number of messages to include in a batch.", + Computed: true, + }, + "max_concurrency": schema.Float64Attribute{ + Description: "Maximum number of concurrent consumers that may consume from this Queue. Set to `null` to automatically opt in to the platform's maximum (recommended).", + Computed: true, + }, + "max_retries": schema.Float64Attribute{ + Description: "The maximum number of retries", + Computed: true, + }, + "max_wait_time_ms": schema.Float64Attribute{ + Description: "The number of milliseconds to wait for a batch to fill up before attempting to deliver it", + Computed: true, + }, + "retry_delay": schema.Float64Attribute{ + Description: "The number of seconds to delay before making the message available for another attempt.", + Computed: true, + }, + "visibility_timeout_ms": schema.Float64Attribute{ + Description: "The number of milliseconds that a message is exclusively leased. After the timeout, the message becomes available for another attempt.", + Computed: true, + }, + }, }, }, } diff --git a/internal/services/r2_bucket/resource.go b/internal/services/r2_bucket/resource.go index efbcb012d9..dc2b2c0ff9 100644 --- a/internal/services/r2_bucket/resource.go +++ b/internal/services/r2_bucket/resource.go @@ -223,11 +223,13 @@ func (r *R2BucketResource) ImportState(ctx context.Context, req resource.ImportS path_account_id := "" path_bucket_name := "" + jurisdiction := "default" diags := importpath.ParseImportID( req.ID, - "/", + "//", &path_account_id, &path_bucket_name, + &jurisdiction, ) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -237,6 +239,12 @@ func (r *R2BucketResource) ImportState(ctx context.Context, req resource.ImportS data.AccountID = types.StringValue(path_account_id) data.Name = types.StringValue(path_bucket_name) + if jurisdiction == "default" { + data.Jurisdiction = types.StringValue("default") + } else { + data.Jurisdiction = types.StringValue(jurisdiction) + } + res := new(http.Response) env := R2BucketResultEnvelope{*data} _, err := r.client.R2.Buckets.Get( @@ -245,6 +253,7 @@ func (r *R2BucketResource) ImportState(ctx context.Context, req resource.ImportS r2.BucketGetParams{ AccountID: cloudflare.F(path_account_id), }, + option.WithHeader(jurisdictionHTTPHeaderName, data.Jurisdiction.ValueString()), option.WithResponseBodyInto(&res), option.WithMiddleware(logging.Middleware(ctx)), ) diff --git a/internal/services/r2_bucket/resource_test.go b/internal/services/r2_bucket/resource_test.go index 29fcca102b..f8b0f22426 100644 --- a/internal/services/r2_bucket/resource_test.go +++ b/internal/services/r2_bucket/resource_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strings" "testing" "github.com/aws/aws-sdk-go-v2/aws" @@ -15,6 +16,7 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/acctest" "github.com/cloudflare/terraform-provider-cloudflare/internal/utils" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" ) func TestMain(m *testing.M) { @@ -120,12 +122,15 @@ func TestAccCloudflareR2Bucket_Basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "location", "ENAM"), ), }, - // { - // ResourceName: resourceName, - // ImportStateIdPrefix: fmt.Sprintf("%s/", accountID), - // ImportState: true, - // ImportStateVerify: true, - // }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(*terraform.State) (string, error) { + return strings.Join([]string{accountID, rnd, "default"}, "/"), nil + }, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "storage_class"}, + }, }, }) } @@ -172,6 +177,15 @@ func TestAccCloudflareR2Bucket_Jurisdiction(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "id", rnd), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(*terraform.State) (string, error) { + return strings.Join([]string{accountID, rnd, "eu"}, "/"), nil + }, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"storage_class"}, + }, }, }) } diff --git a/internal/services/r2_bucket_cors/data_source.go b/internal/services/r2_bucket_cors/data_source.go new file mode 100644 index 0000000000..2a80985019 --- /dev/null +++ b/internal/services/r2_bucket_cors/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type R2BucketCORSDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*R2BucketCORSDataSource)(nil) + +func NewR2BucketCORSDataSource() datasource.DataSource { + return &R2BucketCORSDataSource{} +} + +func (d *R2BucketCORSDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_cors" +} + +func (d *R2BucketCORSDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *R2BucketCORSDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *R2BucketCORSDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketCORSResultDataSourceEnvelope{*data} + _, err := d.client.R2.Buckets.CORS.Get( + ctx, + data.BucketName.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/r2_bucket_cors/data_source_model.go b/internal/services/r2_bucket_cors/data_source_model.go new file mode 100644 index 0000000000..a69a30106f --- /dev/null +++ b/internal/services/r2_bucket_cors/data_source_model.go @@ -0,0 +1,44 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketCORSResultDataSourceEnvelope struct { + Result R2BucketCORSDataSourceModel `json:"result,computed"` +} + +type R2BucketCORSDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketCORSRulesDataSourceModel] `tfsdk:"rules" json:"rules,computed"` +} + +func (m *R2BucketCORSDataSourceModel) toReadParams(_ context.Context) (params r2.BucketCORSGetParams, diags diag.Diagnostics) { + params = r2.BucketCORSGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type R2BucketCORSRulesDataSourceModel struct { + Allowed customfield.NestedObject[R2BucketCORSRulesAllowedDataSourceModel] `tfsdk:"allowed" json:"allowed,computed"` + ID types.String `tfsdk:"id" json:"id,computed"` + ExposeHeaders customfield.List[types.String] `tfsdk:"expose_headers" json:"exposeHeaders,computed"` + MaxAgeSeconds types.Float64 `tfsdk:"max_age_seconds" json:"maxAgeSeconds,computed"` +} + +type R2BucketCORSRulesAllowedDataSourceModel struct { + Methods customfield.List[types.String] `tfsdk:"methods" json:"methods,computed"` + Origins customfield.List[types.String] `tfsdk:"origins" json:"origins,computed"` + Headers customfield.List[types.String] `tfsdk:"headers" json:"headers,computed"` +} diff --git a/internal/services/r2_bucket_cors/data_source_schema.go b/internal/services/r2_bucket_cors/data_source_schema.go new file mode 100644 index 0000000000..99f4f501ea --- /dev/null +++ b/internal/services/r2_bucket_cors/data_source_schema.go @@ -0,0 +1,98 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*R2BucketCORSDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketCORSRulesDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "allowed": schema.SingleNestedAttribute{ + Description: "Object specifying allowed origins, methods and headers for this CORS rule.", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketCORSRulesAllowedDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "methods": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Methods header R2 sets when requesting objects in a bucket from a browser.", + Computed: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "GET", + "PUT", + "POST", + "DELETE", + "HEAD", + ), + ), + }, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "origins": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Origin header R2 sets when requesting objects in a bucket from a browser.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "headers": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Headers header R2 sets when requesting objects in this bucket from a browser. Cross-origin requests that include custom headers (e.g. x-user-id) should specify these headers as AllowedHeaders.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + }, + }, + "id": schema.StringAttribute{ + Description: "Identifier for this rule", + Computed: true, + }, + "expose_headers": schema.ListAttribute{ + Description: "Specifies the headers that can be exposed back, and accessed by, the JavaScript making the cross-origin request. If you need to access headers beyond the safelisted response headers, such as Content-Encoding or cf-cache-status, you must specify it here.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "max_age_seconds": schema.Float64Attribute{ + Description: "Specifies the amount of time (in seconds) browsers are allowed to cache CORS preflight responses. Browsers may limit this to 2 hours or less, even if the maximum value (86400) is specified.", + Computed: true, + }, + }, + }, + }, + }, + } +} + +func (d *R2BucketCORSDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *R2BucketCORSDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_cors/data_source_schema_test.go b/internal/services/r2_bucket_cors/data_source_schema_test.go new file mode 100644 index 0000000000..6879384e2d --- /dev/null +++ b/internal/services/r2_bucket_cors/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_cors" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketCORSDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_cors.R2BucketCORSDataSourceModel)(nil) + schema := r2_bucket_cors.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_cors/migrations.go b/internal/services/r2_bucket_cors/migrations.go new file mode 100644 index 0000000000..28744d3203 --- /dev/null +++ b/internal/services/r2_bucket_cors/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*R2BucketCORSResource)(nil) + +func (r *R2BucketCORSResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/r2_bucket_cors/model.go b/internal/services/r2_bucket_cors/model.go new file mode 100644 index 0000000000..f4fbd34d12 --- /dev/null +++ b/internal/services/r2_bucket_cors/model.go @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketCORSResultEnvelope struct { + Result R2BucketCORSModel `json:"result"` +} + +type R2BucketCORSModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketCORSRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` +} + +func (m R2BucketCORSModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m R2BucketCORSModel) MarshalJSONForUpdate(state R2BucketCORSModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type R2BucketCORSRulesModel struct { + Allowed *R2BucketCORSRulesAllowedModel `tfsdk:"allowed" json:"allowed,required"` + ID types.String `tfsdk:"id" json:"id,optional"` + ExposeHeaders *[]types.String `tfsdk:"expose_headers" json:"exposeHeaders,optional"` + MaxAgeSeconds types.Float64 `tfsdk:"max_age_seconds" json:"maxAgeSeconds,optional"` +} + +type R2BucketCORSRulesAllowedModel struct { + Methods *[]types.String `tfsdk:"methods" json:"methods,required"` + Origins *[]types.String `tfsdk:"origins" json:"origins,required"` + Headers *[]types.String `tfsdk:"headers" json:"headers,optional"` +} diff --git a/internal/services/r2_bucket_cors/resource.go b/internal/services/r2_bucket_cors/resource.go new file mode 100644 index 0000000000..edbdc82f23 --- /dev/null +++ b/internal/services/r2_bucket_cors/resource.go @@ -0,0 +1,212 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*R2BucketCORSResource)(nil) +var _ resource.ResourceWithModifyPlan = (*R2BucketCORSResource)(nil) + +func NewResource() resource.Resource { + return &R2BucketCORSResource{} +} + +// R2BucketCORSResource defines the resource implementation. +type R2BucketCORSResource struct { + client *cloudflare.Client +} + +func (r *R2BucketCORSResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_cors" +} + +func (r *R2BucketCORSResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *R2BucketCORSResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *R2BucketCORSModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketCORSResultEnvelope{*data} + _, err = r.client.R2.Buckets.CORS.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketCORSUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketCORSResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *R2BucketCORSModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *R2BucketCORSModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketCORSResultEnvelope{*data} + _, err = r.client.R2.Buckets.CORS.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketCORSUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketCORSResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *R2BucketCORSModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketCORSResultEnvelope{*data} + _, err := r.client.R2.Buckets.CORS.Get( + ctx, + data.BucketName.ValueString(), + r2.BucketCORSGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketCORSResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *R2BucketCORSModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.R2.Buckets.CORS.Delete( + ctx, + data.BucketName.ValueString(), + r2.BucketCORSDeleteParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketCORSResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/r2_bucket_cors/resource_schema_test.go b/internal/services/r2_bucket_cors/resource_schema_test.go new file mode 100644 index 0000000000..9c6fc95618 --- /dev/null +++ b/internal/services/r2_bucket_cors/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_cors" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketCORSModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_cors.R2BucketCORSModel)(nil) + schema := r2_bucket_cors.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_cors/schema.go b/internal/services/r2_bucket_cors/schema.go new file mode 100644 index 0000000000..2d4e4c1531 --- /dev/null +++ b/internal/services/r2_bucket_cors/schema.go @@ -0,0 +1,100 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_cors + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ resource.ResourceWithConfigValidators = (*R2BucketCORSResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectListType[R2BucketCORSRulesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "allowed": schema.SingleNestedAttribute{ + Description: "Object specifying allowed origins, methods and headers for this CORS rule.", + Required: true, + Attributes: map[string]schema.Attribute{ + "methods": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Methods header R2 sets when requesting objects in a bucket from a browser.", + Required: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "GET", + "PUT", + "POST", + "DELETE", + "HEAD", + ), + ), + }, + ElementType: types.StringType, + }, + "origins": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Origin header R2 sets when requesting objects in a bucket from a browser.", + Required: true, + ElementType: types.StringType, + }, + "headers": schema.ListAttribute{ + Description: "Specifies the value for the Access-Control-Allow-Headers header R2 sets when requesting objects in this bucket from a browser. Cross-origin requests that include custom headers (e.g. x-user-id) should specify these headers as AllowedHeaders.", + Optional: true, + ElementType: types.StringType, + }, + }, + }, + "id": schema.StringAttribute{ + Description: "Identifier for this rule", + Optional: true, + }, + "expose_headers": schema.ListAttribute{ + Description: "Specifies the headers that can be exposed back, and accessed by, the JavaScript making the cross-origin request. If you need to access headers beyond the safelisted response headers, such as Content-Encoding or cf-cache-status, you must specify it here.", + Optional: true, + ElementType: types.StringType, + }, + "max_age_seconds": schema.Float64Attribute{ + Description: "Specifies the amount of time (in seconds) browsers are allowed to cache CORS preflight responses. Browsers may limit this to 2 hours or less, even if the maximum value (86400) is specified.", + Optional: true, + }, + }, + }, + PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, + }, + }, + } +} + +func (r *R2BucketCORSResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *R2BucketCORSResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_event_notification/data_source.go b/internal/services/r2_bucket_event_notification/data_source.go new file mode 100644 index 0000000000..6ea7986812 --- /dev/null +++ b/internal/services/r2_bucket_event_notification/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type R2BucketEventNotificationDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*R2BucketEventNotificationDataSource)(nil) + +func NewR2BucketEventNotificationDataSource() datasource.DataSource { + return &R2BucketEventNotificationDataSource{} +} + +func (d *R2BucketEventNotificationDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_event_notification" +} + +func (d *R2BucketEventNotificationDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *R2BucketEventNotificationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *R2BucketEventNotificationDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketEventNotificationResultDataSourceEnvelope{*data} + _, err := d.client.R2.Buckets.EventNotifications.Get( + ctx, + data.BucketName.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/r2_bucket_event_notification/data_source_model.go b/internal/services/r2_bucket_event_notification/data_source_model.go new file mode 100644 index 0000000000..f31e514d29 --- /dev/null +++ b/internal/services/r2_bucket_event_notification/data_source_model.go @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketEventNotificationResultDataSourceEnvelope struct { + Result R2BucketEventNotificationDataSourceModel `json:"result,computed"` +} + +type R2BucketEventNotificationDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required" json:"bucketName"` + Queues customfield.NestedObjectList[R2BucketEventNotificationQueuesDataSourceModel] `tfsdk:"queues" json:"queues,computed"` +} + +func (m *R2BucketEventNotificationDataSourceModel) toReadParams(_ context.Context) (params r2.BucketEventNotificationGetParams, diags diag.Diagnostics) { + params = r2.BucketEventNotificationGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type R2BucketEventNotificationQueuesDataSourceModel struct { + QueueID types.String `tfsdk:"queue_id" json:"queueId,computed"` + QueueName types.String `tfsdk:"queue_name" json:"queueName,computed"` + Rules customfield.NestedObjectList[R2BucketEventNotificationQueuesRulesDataSourceModel] `tfsdk:"rules" json:"rules,computed"` +} + +type R2BucketEventNotificationQueuesRulesDataSourceModel struct { + Actions customfield.List[types.String] `tfsdk:"actions" json:"actions,computed"` + CreatedAt types.String `tfsdk:"created_at" json:"createdAt,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` + RuleID types.String `tfsdk:"rule_id" json:"ruleId,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` +} diff --git a/internal/services/r2_bucket_event_notification/data_source_schema.go b/internal/services/r2_bucket_event_notification/data_source_schema.go new file mode 100644 index 0000000000..119321a5e4 --- /dev/null +++ b/internal/services/r2_bucket_event_notification/data_source_schema.go @@ -0,0 +1,102 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ datasource.DataSourceWithConfigValidators = (*R2BucketEventNotificationDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + }, + "queues": schema.ListNestedAttribute{ + Description: "List of queues associated with the bucket.", + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketEventNotificationQueuesDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "queue_id": schema.StringAttribute{ + Description: "Queue ID", + Computed: true, + }, + "queue_name": schema.StringAttribute{ + Description: "Name of the queue", + Computed: true, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketEventNotificationQueuesRulesDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "actions": schema.ListAttribute{ + Description: "Array of R2 object actions that will trigger notifications", + Computed: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "PutObject", + "CopyObject", + "DeleteObject", + "CompleteMultipartUpload", + "LifecycleDeletion", + ), + ), + }, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "created_at": schema.StringAttribute{ + Description: "Timestamp when the rule was created", + Computed: true, + }, + "description": schema.StringAttribute{ + Description: "A description that can be used to identify the event notification rule after creation", + Computed: true, + }, + "prefix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this prefix", + Computed: true, + }, + "rule_id": schema.StringAttribute{ + Description: "Rule ID", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this suffix", + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (d *R2BucketEventNotificationDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *R2BucketEventNotificationDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_event_notification/data_source_schema_test.go b/internal/services/r2_bucket_event_notification/data_source_schema_test.go new file mode 100644 index 0000000000..d389b2ccec --- /dev/null +++ b/internal/services/r2_bucket_event_notification/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_event_notification" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketEventNotificationDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_event_notification.R2BucketEventNotificationDataSourceModel)(nil) + schema := r2_bucket_event_notification.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_event_notification/migrations.go b/internal/services/r2_bucket_event_notification/migrations.go new file mode 100644 index 0000000000..711b286cb8 --- /dev/null +++ b/internal/services/r2_bucket_event_notification/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*R2BucketEventNotificationResource)(nil) + +func (r *R2BucketEventNotificationResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/r2_bucket_event_notification/model.go b/internal/services/r2_bucket_event_notification/model.go new file mode 100644 index 0000000000..6f298d3b4e --- /dev/null +++ b/internal/services/r2_bucket_event_notification/model.go @@ -0,0 +1,51 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketEventNotificationResultEnvelope struct { + Result R2BucketEventNotificationModel `json:"result"` +} + +type R2BucketEventNotificationModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + QueueID types.String `tfsdk:"queue_id" path:"queue_id,optional"` + Rules customfield.NestedObjectList[R2BucketEventNotificationRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` + Queues customfield.NestedObjectList[R2BucketEventNotificationQueuesModel] `tfsdk:"queues" json:"queues,computed"` +} + +func (m R2BucketEventNotificationModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m R2BucketEventNotificationModel) MarshalJSONForUpdate(state R2BucketEventNotificationModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type R2BucketEventNotificationRulesModel struct { + Actions *[]types.String `tfsdk:"actions" json:"actions,required"` + Description types.String `tfsdk:"description" json:"description,optional"` + Prefix types.String `tfsdk:"prefix" json:"prefix,optional"` + Suffix types.String `tfsdk:"suffix" json:"suffix,optional"` +} + +type R2BucketEventNotificationQueuesModel struct { + QueueID types.String `tfsdk:"queue_id" json:"queueId,computed"` + QueueName types.String `tfsdk:"queue_name" json:"queueName,computed"` + Rules customfield.NestedObjectList[R2BucketEventNotificationQueuesRulesModel] `tfsdk:"rules" json:"rules,computed"` +} + +type R2BucketEventNotificationQueuesRulesModel struct { + Actions customfield.List[types.String] `tfsdk:"actions" json:"actions,computed"` + CreatedAt types.String `tfsdk:"created_at" json:"createdAt,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` + RuleID types.String `tfsdk:"rule_id" json:"ruleId,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` +} diff --git a/internal/services/r2_bucket_event_notification/resource.go b/internal/services/r2_bucket_event_notification/resource.go new file mode 100644 index 0000000000..156b680016 --- /dev/null +++ b/internal/services/r2_bucket_event_notification/resource.go @@ -0,0 +1,215 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*R2BucketEventNotificationResource)(nil) +var _ resource.ResourceWithModifyPlan = (*R2BucketEventNotificationResource)(nil) + +func NewResource() resource.Resource { + return &R2BucketEventNotificationResource{} +} + +// R2BucketEventNotificationResource defines the resource implementation. +type R2BucketEventNotificationResource struct { + client *cloudflare.Client +} + +func (r *R2BucketEventNotificationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_event_notification" +} + +func (r *R2BucketEventNotificationResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *R2BucketEventNotificationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *R2BucketEventNotificationModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketEventNotificationResultEnvelope{*data} + _, err = r.client.R2.Buckets.EventNotifications.Update( + ctx, + data.BucketName.ValueString(), + data.QueueID.ValueString(), + r2.BucketEventNotificationUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketEventNotificationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *R2BucketEventNotificationModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *R2BucketEventNotificationModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketEventNotificationResultEnvelope{*data} + _, err = r.client.R2.Buckets.EventNotifications.Update( + ctx, + data.BucketName.ValueString(), + data.QueueID.ValueString(), + r2.BucketEventNotificationUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketEventNotificationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *R2BucketEventNotificationModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketEventNotificationResultEnvelope{*data} + _, err := r.client.R2.Buckets.EventNotifications.Get( + ctx, + data.BucketName.ValueString(), + r2.BucketEventNotificationGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketEventNotificationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *R2BucketEventNotificationModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.R2.Buckets.EventNotifications.Delete( + ctx, + data.BucketName.ValueString(), + data.QueueID.ValueString(), + r2.BucketEventNotificationDeleteParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketEventNotificationResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/r2_bucket_event_notification/resource_schema_test.go b/internal/services/r2_bucket_event_notification/resource_schema_test.go new file mode 100644 index 0000000000..5dff950e0e --- /dev/null +++ b/internal/services/r2_bucket_event_notification/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_event_notification" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketEventNotificationModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_event_notification.R2BucketEventNotificationModel)(nil) + schema := r2_bucket_event_notification.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_event_notification/schema.go b/internal/services/r2_bucket_event_notification/schema.go new file mode 100644 index 0000000000..533fb7b9dc --- /dev/null +++ b/internal/services/r2_bucket_event_notification/schema.go @@ -0,0 +1,151 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_event_notification + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var _ resource.ResourceWithConfigValidators = (*R2BucketEventNotificationResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "queue_id": schema.StringAttribute{ + Description: "Queue ID", + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "rules": schema.ListNestedAttribute{ + Description: "Array of rules to drive notifications", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectListType[R2BucketEventNotificationRulesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "actions": schema.ListAttribute{ + Description: "Array of R2 object actions that will trigger notifications", + Required: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "PutObject", + "CopyObject", + "DeleteObject", + "CompleteMultipartUpload", + "LifecycleDeletion", + ), + ), + }, + ElementType: types.StringType, + }, + "description": schema.StringAttribute{ + Description: "A description that can be used to identify the event notification rule after creation", + Optional: true, + }, + "prefix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this prefix", + Optional: true, + }, + "suffix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this suffix", + Optional: true, + }, + }, + }, + PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, + }, + "queues": schema.ListNestedAttribute{ + Description: "List of queues associated with the bucket.", + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketEventNotificationQueuesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "queue_id": schema.StringAttribute{ + Description: "Queue ID", + Computed: true, + }, + "queue_name": schema.StringAttribute{ + Description: "Name of the queue", + Computed: true, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketEventNotificationQueuesRulesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "actions": schema.ListAttribute{ + Description: "Array of R2 object actions that will trigger notifications", + Computed: true, + Validators: []validator.List{ + listvalidator.ValueStringsAre( + stringvalidator.OneOfCaseInsensitive( + "PutObject", + "CopyObject", + "DeleteObject", + "CompleteMultipartUpload", + "LifecycleDeletion", + ), + ), + }, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "created_at": schema.StringAttribute{ + Description: "Timestamp when the rule was created", + Computed: true, + }, + "description": schema.StringAttribute{ + Description: "A description that can be used to identify the event notification rule after creation", + Computed: true, + }, + "prefix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this prefix", + Computed: true, + }, + "rule_id": schema.StringAttribute{ + Description: "Rule ID", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "Notifications will be sent only for objects with this suffix", + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (r *R2BucketEventNotificationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *R2BucketEventNotificationResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_lifecycle/data_source.go b/internal/services/r2_bucket_lifecycle/data_source.go new file mode 100644 index 0000000000..31706dfe43 --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type R2BucketLifecycleDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*R2BucketLifecycleDataSource)(nil) + +func NewR2BucketLifecycleDataSource() datasource.DataSource { + return &R2BucketLifecycleDataSource{} +} + +func (d *R2BucketLifecycleDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_lifecycle" +} + +func (d *R2BucketLifecycleDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *R2BucketLifecycleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *R2BucketLifecycleDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketLifecycleResultDataSourceEnvelope{*data} + _, err := d.client.R2.Buckets.Lifecycle.Get( + ctx, + data.BucketName.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/r2_bucket_lifecycle/data_source_model.go b/internal/services/r2_bucket_lifecycle/data_source_model.go new file mode 100644 index 0000000000..09ef11d03d --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/data_source_model.go @@ -0,0 +1,75 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketLifecycleResultDataSourceEnvelope struct { + Result R2BucketLifecycleDataSourceModel `json:"result,computed"` +} + +type R2BucketLifecycleDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketLifecycleRulesDataSourceModel] `tfsdk:"rules" json:"rules,computed"` +} + +func (m *R2BucketLifecycleDataSourceModel) toReadParams(_ context.Context) (params r2.BucketLifecycleGetParams, diags diag.Diagnostics) { + params = r2.BucketLifecycleGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type R2BucketLifecycleRulesDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Conditions customfield.NestedObject[R2BucketLifecycleRulesConditionsDataSourceModel] `tfsdk:"conditions" json:"conditions,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + AbortMultipartUploadsTransition customfield.NestedObject[R2BucketLifecycleRulesAbortMultipartUploadsTransitionDataSourceModel] `tfsdk:"abort_multipart_uploads_transition" json:"abortMultipartUploadsTransition,computed"` + DeleteObjectsTransition customfield.NestedObject[R2BucketLifecycleRulesDeleteObjectsTransitionDataSourceModel] `tfsdk:"delete_objects_transition" json:"deleteObjectsTransition,computed"` + StorageClassTransitions customfield.NestedObjectList[R2BucketLifecycleRulesStorageClassTransitionsDataSourceModel] `tfsdk:"storage_class_transitions" json:"storageClassTransitions,computed"` +} + +type R2BucketLifecycleRulesConditionsDataSourceModel struct { + Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` +} + +type R2BucketLifecycleRulesAbortMultipartUploadsTransitionDataSourceModel struct { + Condition customfield.NestedObject[R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionDataSourceModel] `tfsdk:"condition" json:"condition,computed"` +} + +type R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionDataSourceModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,computed"` + Type types.String `tfsdk:"type" json:"type,computed"` +} + +type R2BucketLifecycleRulesDeleteObjectsTransitionDataSourceModel struct { + Condition customfield.NestedObject[R2BucketLifecycleRulesDeleteObjectsTransitionConditionDataSourceModel] `tfsdk:"condition" json:"condition,computed"` +} + +type R2BucketLifecycleRulesDeleteObjectsTransitionConditionDataSourceModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,computed"` + Type types.String `tfsdk:"type" json:"type,computed"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,computed" format:"date"` +} + +type R2BucketLifecycleRulesStorageClassTransitionsDataSourceModel struct { + Condition customfield.NestedObject[R2BucketLifecycleRulesStorageClassTransitionsConditionDataSourceModel] `tfsdk:"condition" json:"condition,computed"` + StorageClass types.String `tfsdk:"storage_class" json:"storageClass,computed"` +} + +type R2BucketLifecycleRulesStorageClassTransitionsConditionDataSourceModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,computed"` + Type types.String `tfsdk:"type" json:"type,computed"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,computed" format:"date"` +} diff --git a/internal/services/r2_bucket_lifecycle/data_source_schema.go b/internal/services/r2_bucket_lifecycle/data_source_schema.go new file mode 100644 index 0000000000..41309ed6c9 --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/data_source_schema.go @@ -0,0 +1,151 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*R2BucketLifecycleDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLifecycleRulesDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Unique identifier for this rule", + Computed: true, + }, + "conditions": schema.SingleNestedAttribute{ + Description: "Conditions that apply to all transitions of this rule", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesConditionsDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "prefix": schema.StringAttribute{ + Description: "Transitions will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads", + Computed: true, + }, + }, + }, + "enabled": schema.BoolAttribute{ + Description: "Whether or not this rule is in effect", + Computed: true, + }, + "abort_multipart_uploads_transition": schema.SingleNestedAttribute{ + Description: "Transition to abort ongoing multipart uploads", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesAbortMultipartUploadsTransitionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Computed: true, + }, + "type": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age"), + }, + }, + }, + }, + }, + }, + "delete_objects_transition": schema.SingleNestedAttribute{ + Description: "Transition to delete objects", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesDeleteObjectsTransitionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesDeleteObjectsTransitionConditionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Computed: true, + }, + "type": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age", "Date"), + }, + }, + "date": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + }, + }, + "storage_class_transitions": schema.ListNestedAttribute{ + Description: "Transitions to change the storage class of objects", + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLifecycleRulesStorageClassTransitionsDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesStorageClassTransitionsConditionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Computed: true, + }, + "type": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age", "Date"), + }, + }, + "date": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + "storage_class": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("InfrequentAccess"), + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (d *R2BucketLifecycleDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *R2BucketLifecycleDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_lifecycle/data_source_schema_test.go b/internal/services/r2_bucket_lifecycle/data_source_schema_test.go new file mode 100644 index 0000000000..64eb3c7840 --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lifecycle" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketLifecycleDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_lifecycle.R2BucketLifecycleDataSourceModel)(nil) + schema := r2_bucket_lifecycle.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_lifecycle/migrations.go b/internal/services/r2_bucket_lifecycle/migrations.go new file mode 100644 index 0000000000..f6d0513add --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*R2BucketLifecycleResource)(nil) + +func (r *R2BucketLifecycleResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/r2_bucket_lifecycle/model.go b/internal/services/r2_bucket_lifecycle/model.go new file mode 100644 index 0000000000..094caf15f8 --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/model.go @@ -0,0 +1,71 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketLifecycleResultEnvelope struct { + Result R2BucketLifecycleModel `json:"result"` +} + +type R2BucketLifecycleModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketLifecycleRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` +} + +func (m R2BucketLifecycleModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m R2BucketLifecycleModel) MarshalJSONForUpdate(state R2BucketLifecycleModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type R2BucketLifecycleRulesModel struct { + ID types.String `tfsdk:"id" json:"id,required"` + Conditions *R2BucketLifecycleRulesConditionsModel `tfsdk:"conditions" json:"conditions,required"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,required"` + AbortMultipartUploadsTransition customfield.NestedObject[R2BucketLifecycleRulesAbortMultipartUploadsTransitionModel] `tfsdk:"abort_multipart_uploads_transition" json:"abortMultipartUploadsTransition,computed_optional"` + DeleteObjectsTransition customfield.NestedObject[R2BucketLifecycleRulesDeleteObjectsTransitionModel] `tfsdk:"delete_objects_transition" json:"deleteObjectsTransition,computed_optional"` + StorageClassTransitions customfield.NestedObjectList[R2BucketLifecycleRulesStorageClassTransitionsModel] `tfsdk:"storage_class_transitions" json:"storageClassTransitions,computed_optional"` +} + +type R2BucketLifecycleRulesConditionsModel struct { + Prefix types.String `tfsdk:"prefix" json:"prefix,required"` +} + +type R2BucketLifecycleRulesAbortMultipartUploadsTransitionModel struct { + Condition customfield.NestedObject[R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionModel] `tfsdk:"condition" json:"condition,computed_optional"` +} + +type R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,required"` + Type types.String `tfsdk:"type" json:"type,required"` +} + +type R2BucketLifecycleRulesDeleteObjectsTransitionModel struct { + Condition customfield.NestedObject[R2BucketLifecycleRulesDeleteObjectsTransitionConditionModel] `tfsdk:"condition" json:"condition,computed_optional"` +} + +type R2BucketLifecycleRulesDeleteObjectsTransitionConditionModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,optional"` + Type types.String `tfsdk:"type" json:"type,required"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,optional" format:"date"` +} + +type R2BucketLifecycleRulesStorageClassTransitionsModel struct { + Condition *R2BucketLifecycleRulesStorageClassTransitionsConditionModel `tfsdk:"condition" json:"condition,required"` + StorageClass types.String `tfsdk:"storage_class" json:"storageClass,required"` +} + +type R2BucketLifecycleRulesStorageClassTransitionsConditionModel struct { + MaxAge types.Int64 `tfsdk:"max_age" json:"maxAge,optional"` + Type types.String `tfsdk:"type" json:"type,required"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,optional" format:"date"` +} diff --git a/internal/services/r2_bucket_lifecycle/resource.go b/internal/services/r2_bucket_lifecycle/resource.go new file mode 100644 index 0000000000..cce954fefc --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/resource.go @@ -0,0 +1,205 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*R2BucketLifecycleResource)(nil) +var _ resource.ResourceWithModifyPlan = (*R2BucketLifecycleResource)(nil) + +func NewResource() resource.Resource { + return &R2BucketLifecycleResource{} +} + +// R2BucketLifecycleResource defines the resource implementation. +type R2BucketLifecycleResource struct { + client *cloudflare.Client +} + +func (r *R2BucketLifecycleResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_lifecycle" +} + +func (r *R2BucketLifecycleResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *R2BucketLifecycleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *R2BucketLifecycleModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketLifecycleResultEnvelope{*data} + _, err = r.client.R2.Buckets.Lifecycle.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketLifecycleUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLifecycleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *R2BucketLifecycleModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *R2BucketLifecycleModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketLifecycleResultEnvelope{*data} + _, err = r.client.R2.Buckets.Lifecycle.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketLifecycleUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLifecycleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *R2BucketLifecycleModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketLifecycleResultEnvelope{*data} + _, err := r.client.R2.Buckets.Lifecycle.Get( + ctx, + data.BucketName.ValueString(), + r2.BucketLifecycleGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLifecycleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + +} + +func (r *R2BucketLifecycleResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if req.State.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "This resource cannot be destroyed from Terraform. If you create this resource, it will be "+ + "present in the API until manually deleted.", + ) + } + if req.Plan.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "Applying this resource destruction will remove the resource from the Terraform state "+ + "but will not change it in the API. If you would like to destroy or reset this resource "+ + "in the API, refer to the documentation for how to do it manually.", + ) + } +} diff --git a/internal/services/r2_bucket_lifecycle/resource_schema_test.go b/internal/services/r2_bucket_lifecycle/resource_schema_test.go new file mode 100644 index 0000000000..207fb6b0a6 --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lifecycle" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketLifecycleModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_lifecycle.R2BucketLifecycleModel)(nil) + schema := r2_bucket_lifecycle.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_lifecycle/schema.go b/internal/services/r2_bucket_lifecycle/schema.go new file mode 100644 index 0000000000..0887a8e17c --- /dev/null +++ b/internal/services/r2_bucket_lifecycle/schema.go @@ -0,0 +1,161 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lifecycle + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*R2BucketLifecycleResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLifecycleRulesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Unique identifier for this rule", + Required: true, + }, + "conditions": schema.SingleNestedAttribute{ + Description: "Conditions that apply to all transitions of this rule", + Required: true, + Attributes: map[string]schema.Attribute{ + "prefix": schema.StringAttribute{ + Description: "Transitions will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads", + Required: true, + }, + }, + }, + "enabled": schema.BoolAttribute{ + Description: "Whether or not this rule is in effect", + Required: true, + }, + "abort_multipart_uploads_transition": schema.SingleNestedAttribute{ + Description: "Transition to abort ongoing multipart uploads", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesAbortMultipartUploadsTransitionModel](ctx), + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesAbortMultipartUploadsTransitionConditionModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Required: true, + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age"), + }, + }, + }, + }, + }, + }, + "delete_objects_transition": schema.SingleNestedAttribute{ + Description: "Transition to delete objects", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesDeleteObjectsTransitionModel](ctx), + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketLifecycleRulesDeleteObjectsTransitionConditionModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age", "Date"), + }, + }, + "date": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + }, + }, + "storage_class_transitions": schema.ListNestedAttribute{ + Description: "Transitions to change the storage class of objects", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLifecycleRulesStorageClassTransitionsModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "condition": schema.SingleNestedAttribute{ + Description: "Condition for lifecycle transitions to apply after an object reaches an age in seconds", + Required: true, + Attributes: map[string]schema.Attribute{ + "max_age": schema.Int64Attribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("Age", "Date"), + }, + }, + "date": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + "storage_class": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("InfrequentAccess"), + }, + }, + }, + }, + }, + }, + }, + PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, + }, + }, + } +} + +func (r *R2BucketLifecycleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *R2BucketLifecycleResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_lock/data_source.go b/internal/services/r2_bucket_lock/data_source.go new file mode 100644 index 0000000000..a947fcc2f7 --- /dev/null +++ b/internal/services/r2_bucket_lock/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type R2BucketLockDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*R2BucketLockDataSource)(nil) + +func NewR2BucketLockDataSource() datasource.DataSource { + return &R2BucketLockDataSource{} +} + +func (d *R2BucketLockDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_lock" +} + +func (d *R2BucketLockDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *R2BucketLockDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *R2BucketLockDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketLockResultDataSourceEnvelope{*data} + _, err := d.client.R2.Buckets.Locks.Get( + ctx, + data.BucketName.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/r2_bucket_lock/data_source_model.go b/internal/services/r2_bucket_lock/data_source_model.go new file mode 100644 index 0000000000..41f416ad6a --- /dev/null +++ b/internal/services/r2_bucket_lock/data_source_model.go @@ -0,0 +1,45 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketLockResultDataSourceEnvelope struct { + Result R2BucketLockDataSourceModel `json:"result,computed"` +} + +type R2BucketLockDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketLockRulesDataSourceModel] `tfsdk:"rules" json:"rules,computed"` +} + +func (m *R2BucketLockDataSourceModel) toReadParams(_ context.Context) (params r2.BucketLockGetParams, diags diag.Diagnostics) { + params = r2.BucketLockGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type R2BucketLockRulesDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Condition customfield.NestedObject[R2BucketLockRulesConditionDataSourceModel] `tfsdk:"condition" json:"condition,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Prefix types.String `tfsdk:"prefix" json:"prefix,computed"` +} + +type R2BucketLockRulesConditionDataSourceModel struct { + MaxAgeSeconds types.Int64 `tfsdk:"max_age_seconds" json:"maxAgeSeconds,computed"` + Type types.String `tfsdk:"type" json:"type,computed"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,computed" format:"date"` +} diff --git a/internal/services/r2_bucket_lock/data_source_schema.go b/internal/services/r2_bucket_lock/data_source_schema.go new file mode 100644 index 0000000000..fc0c4393a5 --- /dev/null +++ b/internal/services/r2_bucket_lock/data_source_schema.go @@ -0,0 +1,83 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*R2BucketLockDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLockRulesDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Unique identifier for this rule", + Computed: true, + }, + "condition": schema.SingleNestedAttribute{ + Description: "Condition to apply a lock rule to an object for how long in seconds", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketLockRulesConditionDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "max_age_seconds": schema.Int64Attribute{ + Computed: true, + }, + "type": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "Age", + "Date", + "Indefinite", + ), + }, + }, + "date": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + "enabled": schema.BoolAttribute{ + Description: "Whether or not this rule is in effect", + Computed: true, + }, + "prefix": schema.StringAttribute{ + Description: "Rule will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads", + Computed: true, + }, + }, + }, + }, + }, + } +} + +func (d *R2BucketLockDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *R2BucketLockDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_lock/data_source_schema_test.go b/internal/services/r2_bucket_lock/data_source_schema_test.go new file mode 100644 index 0000000000..e3f921ab0c --- /dev/null +++ b/internal/services/r2_bucket_lock/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lock" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketLockDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_lock.R2BucketLockDataSourceModel)(nil) + schema := r2_bucket_lock.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_lock/migrations.go b/internal/services/r2_bucket_lock/migrations.go new file mode 100644 index 0000000000..c56d788bfe --- /dev/null +++ b/internal/services/r2_bucket_lock/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*R2BucketLockResource)(nil) + +func (r *R2BucketLockResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/r2_bucket_lock/model.go b/internal/services/r2_bucket_lock/model.go new file mode 100644 index 0000000000..f42652622d --- /dev/null +++ b/internal/services/r2_bucket_lock/model.go @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketLockResultEnvelope struct { + Result R2BucketLockModel `json:"result"` +} + +type R2BucketLockModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Rules customfield.NestedObjectList[R2BucketLockRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` +} + +func (m R2BucketLockModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m R2BucketLockModel) MarshalJSONForUpdate(state R2BucketLockModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type R2BucketLockRulesModel struct { + ID types.String `tfsdk:"id" json:"id,required"` + Condition *R2BucketLockRulesConditionModel `tfsdk:"condition" json:"condition,required"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,required"` + Prefix types.String `tfsdk:"prefix" json:"prefix,optional"` +} + +type R2BucketLockRulesConditionModel struct { + MaxAgeSeconds types.Int64 `tfsdk:"max_age_seconds" json:"maxAgeSeconds,optional"` + Type types.String `tfsdk:"type" json:"type,required"` + Date timetypes.RFC3339 `tfsdk:"date" json:"date,optional" format:"date"` +} diff --git a/internal/services/r2_bucket_lock/resource.go b/internal/services/r2_bucket_lock/resource.go new file mode 100644 index 0000000000..0ae716f90e --- /dev/null +++ b/internal/services/r2_bucket_lock/resource.go @@ -0,0 +1,205 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*R2BucketLockResource)(nil) +var _ resource.ResourceWithModifyPlan = (*R2BucketLockResource)(nil) + +func NewResource() resource.Resource { + return &R2BucketLockResource{} +} + +// R2BucketLockResource defines the resource implementation. +type R2BucketLockResource struct { + client *cloudflare.Client +} + +func (r *R2BucketLockResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_lock" +} + +func (r *R2BucketLockResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *R2BucketLockResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *R2BucketLockModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketLockResultEnvelope{*data} + _, err = r.client.R2.Buckets.Locks.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketLockUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLockResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *R2BucketLockModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *R2BucketLockModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketLockResultEnvelope{*data} + _, err = r.client.R2.Buckets.Locks.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketLockUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLockResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *R2BucketLockModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketLockResultEnvelope{*data} + _, err := r.client.R2.Buckets.Locks.Get( + ctx, + data.BucketName.ValueString(), + r2.BucketLockGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketLockResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + +} + +func (r *R2BucketLockResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if req.State.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "This resource cannot be destroyed from Terraform. If you create this resource, it will be "+ + "present in the API until manually deleted.", + ) + } + if req.Plan.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "Applying this resource destruction will remove the resource from the Terraform state "+ + "but will not change it in the API. If you would like to destroy or reset this resource "+ + "in the API, refer to the documentation for how to do it manually.", + ) + } +} diff --git a/internal/services/r2_bucket_lock/resource_schema_test.go b/internal/services/r2_bucket_lock/resource_schema_test.go new file mode 100644 index 0000000000..6320637bd4 --- /dev/null +++ b/internal/services/r2_bucket_lock/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_lock" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketLockModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_lock.R2BucketLockModel)(nil) + schema := r2_bucket_lock.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_lock/schema.go b/internal/services/r2_bucket_lock/schema.go new file mode 100644 index 0000000000..5371108d45 --- /dev/null +++ b/internal/services/r2_bucket_lock/schema.go @@ -0,0 +1,89 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_lock + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*R2BucketLockResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "rules": schema.ListNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectListType[R2BucketLockRulesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Unique identifier for this rule", + Required: true, + }, + "condition": schema.SingleNestedAttribute{ + Description: "Condition to apply a lock rule to an object for how long in seconds", + Required: true, + Attributes: map[string]schema.Attribute{ + "max_age_seconds": schema.Int64Attribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "Age", + "Date", + "Indefinite", + ), + }, + }, + "date": schema.StringAttribute{ + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + "enabled": schema.BoolAttribute{ + Description: "Whether or not this rule is in effect", + Required: true, + }, + "prefix": schema.StringAttribute{ + Description: "Rule will only apply to objects/uploads in the bucket that start with the given prefix, an empty prefix can be provided to scope rule to all objects/uploads", + Optional: true, + }, + }, + }, + PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, + }, + }, + } +} + +func (r *R2BucketLockResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *R2BucketLockResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_sippy/data_source.go b/internal/services/r2_bucket_sippy/data_source.go new file mode 100644 index 0000000000..0e1b17873f --- /dev/null +++ b/internal/services/r2_bucket_sippy/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type R2BucketSippyDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*R2BucketSippyDataSource)(nil) + +func NewR2BucketSippyDataSource() datasource.DataSource { + return &R2BucketSippyDataSource{} +} + +func (d *R2BucketSippyDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_sippy" +} + +func (d *R2BucketSippyDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *R2BucketSippyDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *R2BucketSippyDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketSippyResultDataSourceEnvelope{*data} + _, err := d.client.R2.Buckets.Sippy.Get( + ctx, + data.BucketName.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/r2_bucket_sippy/data_source_model.go b/internal/services/r2_bucket_sippy/data_source_model.go new file mode 100644 index 0000000000..75eec64a24 --- /dev/null +++ b/internal/services/r2_bucket_sippy/data_source_model.go @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketSippyResultDataSourceEnvelope struct { + Result R2BucketSippyDataSourceModel `json:"result,computed"` +} + +type R2BucketSippyDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Destination customfield.NestedObject[R2BucketSippyDestinationDataSourceModel] `tfsdk:"destination" json:"destination,computed"` + Source customfield.NestedObject[R2BucketSippySourceDataSourceModel] `tfsdk:"source" json:"source,computed"` +} + +func (m *R2BucketSippyDataSourceModel) toReadParams(_ context.Context) (params r2.BucketSippyGetParams, diags diag.Diagnostics) { + params = r2.BucketSippyGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type R2BucketSippyDestinationDataSourceModel struct { + AccessKeyID types.String `tfsdk:"access_key_id" json:"accessKeyId,computed"` + Account types.String `tfsdk:"account" json:"account,computed"` + Bucket types.String `tfsdk:"bucket" json:"bucket,computed"` + Provider types.String `tfsdk:"provider" json:"provider,computed"` +} + +type R2BucketSippySourceDataSourceModel struct { + Bucket types.String `tfsdk:"bucket" json:"bucket,computed"` + Provider types.String `tfsdk:"provider" json:"provider,computed"` + Region types.String `tfsdk:"region" json:"region,computed"` +} diff --git a/internal/services/r2_bucket_sippy/data_source_schema.go b/internal/services/r2_bucket_sippy/data_source_schema.go new file mode 100644 index 0000000000..fac076890d --- /dev/null +++ b/internal/services/r2_bucket_sippy/data_source_schema.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*R2BucketSippyDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + }, + "enabled": schema.BoolAttribute{ + Description: "State of Sippy for this bucket", + Computed: true, + }, + "destination": schema.SingleNestedAttribute{ + Description: "Details about the configured destination bucket", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketSippyDestinationDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "access_key_id": schema.StringAttribute{ + Description: "ID of the Cloudflare API token used when writing objects to this\nbucket\n", + Computed: true, + }, + "account": schema.StringAttribute{ + Computed: true, + }, + "bucket": schema.StringAttribute{ + Description: "Name of the bucket on the provider", + Computed: true, + }, + "provider": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("r2"), + }, + }, + }, + }, + "source": schema.SingleNestedAttribute{ + Description: "Details about the configured source bucket", + Computed: true, + CustomType: customfield.NewNestedObjectType[R2BucketSippySourceDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "bucket": schema.StringAttribute{ + Description: "Name of the bucket on the provider", + Computed: true, + }, + "provider": schema.StringAttribute{ + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("aws", "gcs"), + }, + }, + "region": schema.StringAttribute{ + Description: "Region where the bucket resides (AWS only)", + Computed: true, + }, + }, + }, + }, + } +} + +func (d *R2BucketSippyDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *R2BucketSippyDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/r2_bucket_sippy/data_source_schema_test.go b/internal/services/r2_bucket_sippy/data_source_schema_test.go new file mode 100644 index 0000000000..13b95ce0c5 --- /dev/null +++ b/internal/services/r2_bucket_sippy/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_sippy" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketSippyDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_sippy.R2BucketSippyDataSourceModel)(nil) + schema := r2_bucket_sippy.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_sippy/migrations.go b/internal/services/r2_bucket_sippy/migrations.go new file mode 100644 index 0000000000..2199ffd3ce --- /dev/null +++ b/internal/services/r2_bucket_sippy/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*R2BucketSippyResource)(nil) + +func (r *R2BucketSippyResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/r2_bucket_sippy/model.go b/internal/services/r2_bucket_sippy/model.go new file mode 100644 index 0000000000..7c00f47304 --- /dev/null +++ b/internal/services/r2_bucket_sippy/model.go @@ -0,0 +1,45 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type R2BucketSippyResultEnvelope struct { + Result R2BucketSippyModel `json:"result"` +} + +type R2BucketSippyModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + BucketName types.String `tfsdk:"bucket_name" path:"bucket_name,required"` + Destination customfield.NestedObject[R2BucketSippyDestinationModel] `tfsdk:"destination" json:"destination,computed_optional"` + Source customfield.NestedObject[R2BucketSippySourceModel] `tfsdk:"source" json:"source,computed_optional"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` +} + +func (m R2BucketSippyModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m R2BucketSippyModel) MarshalJSONForUpdate(state R2BucketSippyModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type R2BucketSippyDestinationModel struct { + AccessKeyID types.String `tfsdk:"access_key_id" json:"accessKeyId,optional"` + Provider types.String `tfsdk:"provider" json:"provider,optional"` + SecretAccessKey types.String `tfsdk:"secret_access_key" json:"secretAccessKey,optional"` +} + +type R2BucketSippySourceModel struct { + AccessKeyID types.String `tfsdk:"access_key_id" json:"accessKeyId,optional"` + Bucket types.String `tfsdk:"bucket" json:"bucket,optional"` + Provider types.String `tfsdk:"provider" json:"provider,optional"` + Region types.String `tfsdk:"region" json:"region,optional"` + SecretAccessKey types.String `tfsdk:"secret_access_key" json:"secretAccessKey,optional"` + ClientEmail types.String `tfsdk:"client_email" json:"clientEmail,optional"` + PrivateKey types.String `tfsdk:"private_key" json:"privateKey,optional"` +} diff --git a/internal/services/r2_bucket_sippy/resource.go b/internal/services/r2_bucket_sippy/resource.go new file mode 100644 index 0000000000..6630376ef9 --- /dev/null +++ b/internal/services/r2_bucket_sippy/resource.go @@ -0,0 +1,212 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/r2" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*R2BucketSippyResource)(nil) +var _ resource.ResourceWithModifyPlan = (*R2BucketSippyResource)(nil) + +func NewResource() resource.Resource { + return &R2BucketSippyResource{} +} + +// R2BucketSippyResource defines the resource implementation. +type R2BucketSippyResource struct { + client *cloudflare.Client +} + +func (r *R2BucketSippyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_r2_bucket_sippy" +} + +func (r *R2BucketSippyResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *R2BucketSippyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *R2BucketSippyModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketSippyResultEnvelope{*data} + _, err = r.client.R2.Buckets.Sippy.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketSippyUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketSippyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *R2BucketSippyModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *R2BucketSippyModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := R2BucketSippyResultEnvelope{*data} + _, err = r.client.R2.Buckets.Sippy.Update( + ctx, + data.BucketName.ValueString(), + r2.BucketSippyUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketSippyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *R2BucketSippyModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := R2BucketSippyResultEnvelope{*data} + _, err := r.client.R2.Buckets.Sippy.Get( + ctx, + data.BucketName.ValueString(), + r2.BucketSippyGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketSippyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *R2BucketSippyModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.R2.Buckets.Sippy.Delete( + ctx, + data.BucketName.ValueString(), + r2.BucketSippyDeleteParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *R2BucketSippyResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/r2_bucket_sippy/resource_schema_test.go b/internal/services/r2_bucket_sippy/resource_schema_test.go new file mode 100644 index 0000000000..960db179e8 --- /dev/null +++ b/internal/services/r2_bucket_sippy/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/r2_bucket_sippy" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestR2BucketSippyModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*r2_bucket_sippy.R2BucketSippyModel)(nil) + schema := r2_bucket_sippy.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/r2_bucket_sippy/schema.go b/internal/services/r2_bucket_sippy/schema.go new file mode 100644 index 0000000000..17ec35f5ac --- /dev/null +++ b/internal/services/r2_bucket_sippy/schema.go @@ -0,0 +1,109 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package r2_bucket_sippy + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*R2BucketSippyResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Account ID", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "bucket_name": schema.StringAttribute{ + Description: "Name of the bucket", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "destination": schema.SingleNestedAttribute{ + Description: "R2 bucket to copy objects to", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketSippyDestinationModel](ctx), + Attributes: map[string]schema.Attribute{ + "access_key_id": schema.StringAttribute{ + Description: "ID of a Cloudflare API token.\nThis is the value labelled \"Access Key ID\" when creating an API\ntoken from the [R2 dashboard](https://dash.cloudflare.com/?to=/:account/r2/api-tokens).\n\nSippy will use this token when writing objects to R2, so it is\nbest to scope this token to the bucket you're enabling Sippy for.\n", + Optional: true, + }, + "provider": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("r2"), + }, + }, + "secret_access_key": schema.StringAttribute{ + Description: "Value of a Cloudflare API token.\nThis is the value labelled \"Secret Access Key\" when creating an API\ntoken from the [R2 dashboard](https://dash.cloudflare.com/?to=/:account/r2/api-tokens).\n\nSippy will use this token when writing objects to R2, so it is\nbest to scope this token to the bucket you're enabling Sippy for.\n", + Optional: true, + }, + }, + PlanModifiers: []planmodifier.Object{objectplanmodifier.RequiresReplace()}, + }, + "source": schema.SingleNestedAttribute{ + Description: "AWS S3 bucket to copy objects from", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[R2BucketSippySourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "access_key_id": schema.StringAttribute{ + Description: "Access Key ID of an IAM credential (ideally scoped to a single S3 bucket)", + Optional: true, + }, + "bucket": schema.StringAttribute{ + Description: "Name of the AWS S3 bucket", + Optional: true, + }, + "provider": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("aws", "gcs"), + }, + }, + "region": schema.StringAttribute{ + Description: "Name of the AWS availability zone", + Optional: true, + }, + "secret_access_key": schema.StringAttribute{ + Description: "Secret Access Key of an IAM credential (ideally scoped to a single S3 bucket)", + Optional: true, + }, + "client_email": schema.StringAttribute{ + Description: "Client email of an IAM credential (ideally scoped to a single GCS bucket)", + Optional: true, + }, + "private_key": schema.StringAttribute{ + Description: "Private Key of an IAM credential (ideally scoped to a single GCS bucket)", + Optional: true, + }, + }, + PlanModifiers: []planmodifier.Object{objectplanmodifier.RequiresReplace()}, + }, + "enabled": schema.BoolAttribute{ + Description: "State of Sippy for this bucket", + Computed: true, + }, + }, + } +} + +func (r *R2BucketSippyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *R2BucketSippyResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/rate_limit/data_source_model.go b/internal/services/rate_limit/data_source_model.go index 35d644fd52..06ef5cf0ff 100644 --- a/internal/services/rate_limit/data_source_model.go +++ b/internal/services/rate_limit/data_source_model.go @@ -16,10 +16,6 @@ type RateLimitResultDataSourceEnvelope struct { Result RateLimitDataSourceModel `json:"result,computed"` } -type RateLimitResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[RateLimitDataSourceModel] `json:"result,computed"` -} - type RateLimitDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RateLimitID types.String `tfsdk:"rate_limit_id" path:"rate_limit_id,optional"` diff --git a/internal/services/regional_hostname/data_source_model.go b/internal/services/regional_hostname/data_source_model.go index 7ca195be29..89f79fbfad 100644 --- a/internal/services/regional_hostname/data_source_model.go +++ b/internal/services/regional_hostname/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/addressing" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type RegionalHostnameResultDataSourceEnvelope struct { Result RegionalHostnameDataSourceModel `json:"result,computed"` } -type RegionalHostnameResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[RegionalHostnameDataSourceModel] `json:"result,computed"` -} - type RegionalHostnameDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` Hostname types.String `tfsdk:"hostname" path:"hostname,computed_optional"` diff --git a/internal/services/resource_group/list_data_source_model.go b/internal/services/resource_group/list_data_source_model.go index 4fac4af5a7..66716d9338 100644 --- a/internal/services/resource_group/list_data_source_model.go +++ b/internal/services/resource_group/list_data_source_model.go @@ -40,4 +40,22 @@ func (m *ResourceGroupsDataSourceModel) toListParams(_ context.Context) (params } type ResourceGroupsResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Scope customfield.NestedObjectList[ResourceGroupsScopeDataSourceModel] `tfsdk:"scope" json:"scope,computed"` + Meta customfield.NestedObject[ResourceGroupsMetaDataSourceModel] `tfsdk:"meta" json:"meta,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` +} + +type ResourceGroupsScopeDataSourceModel struct { + Key types.String `tfsdk:"key" json:"key,computed"` + Objects customfield.NestedObjectList[ResourceGroupsScopeObjectsDataSourceModel] `tfsdk:"objects" json:"objects,computed"` +} + +type ResourceGroupsScopeObjectsDataSourceModel struct { + Key types.String `tfsdk:"key" json:"key,computed"` +} + +type ResourceGroupsMetaDataSourceModel struct { + Key types.String `tfsdk:"key" json:"key,computed"` + Value types.String `tfsdk:"value" json:"value,computed"` } diff --git a/internal/services/resource_group/list_data_source_schema.go b/internal/services/resource_group/list_data_source_schema.go index 29b465ce3d..4f00c8f46a 100644 --- a/internal/services/resource_group/list_data_source_schema.go +++ b/internal/services/resource_group/list_data_source_schema.go @@ -41,7 +41,55 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectListType[ResourceGroupsResultDataSourceModel](ctx), NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{}, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier of the group.", + Computed: true, + }, + "scope": schema.ListNestedAttribute{ + Description: "The scope associated to the resource group", + Computed: true, + CustomType: customfield.NewNestedObjectListType[ResourceGroupsScopeDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Description: "This is a combination of pre-defined resource name and identifier (like Account ID etc.)", + Computed: true, + }, + "objects": schema.ListNestedAttribute{ + Description: "A list of scope objects for additional context.", + Computed: true, + CustomType: customfield.NewNestedObjectListType[ResourceGroupsScopeObjectsDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Description: "This is a combination of pre-defined resource name and identifier (like Zone ID etc.)", + Computed: true, + }, + }, + }, + }, + }, + }, + }, + "meta": schema.SingleNestedAttribute{ + Description: "Attributes associated to the resource group.", + Computed: true, + CustomType: customfield.NewNestedObjectType[ResourceGroupsMetaDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "key": schema.StringAttribute{ + Computed: true, + }, + "value": schema.StringAttribute{ + Computed: true, + }, + }, + }, + "name": schema.StringAttribute{ + Description: "Name of the resource group.", + Computed: true, + }, + }, }, }, }, diff --git a/internal/services/ruleset/data_source_model.go b/internal/services/ruleset/data_source_model.go index d04de97ee6..a7df65e963 100644 --- a/internal/services/ruleset/data_source_model.go +++ b/internal/services/ruleset/data_source_model.go @@ -16,10 +16,6 @@ type RulesetResultDataSourceEnvelope struct { Result RulesetDataSourceModel `json:"result,computed"` } -type RulesetResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[RulesetDataSourceModel] `json:"result,computed"` -} - type RulesetDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RulesetID types.String `tfsdk:"ruleset_id" path:"ruleset_id,optional"` diff --git a/internal/services/ruleset/model.go b/internal/services/ruleset/model.go index 660f3c8c2f..19c006add1 100644 --- a/internal/services/ruleset/model.go +++ b/internal/services/ruleset/model.go @@ -33,13 +33,13 @@ func (m RulesetModel) MarshalJSONForUpdate(state RulesetModel) (data []byte, err type RulesetRulesModel struct { ID types.String `tfsdk:"id" json:"id,computed"` - Action types.String `tfsdk:"action" json:"action,computed_optional"` + Action types.String `tfsdk:"action" json:"action,optional"` ActionParameters *RulesetRulesActionParametersModel `tfsdk:"action_parameters" json:"action_parameters,optional"` Categories customfield.List[types.String] `tfsdk:"categories" json:"categories,computed"` Description types.String `tfsdk:"description" json:"description,computed_optional"` Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed_optional"` ExposedCredentialCheck *RulesetRulesExposedCredentialCheckModel `tfsdk:"exposed_credential_check" json:"exposed_credential_check,optional"` - Expression types.String `tfsdk:"expression" json:"expression,computed_optional"` + Expression types.String `tfsdk:"expression" json:"expression,optional"` Logging *RulesetRulesLoggingModel `tfsdk:"logging" json:"logging,optional"` Ratelimit *RulesetRulesRatelimitModel `tfsdk:"ratelimit" json:"ratelimit,optional"` Ref types.String `tfsdk:"ref" json:"ref,computed_optional"` @@ -53,7 +53,7 @@ type RulesetRulesActionParametersModel struct { Overrides *RulesetRulesActionParametersOverridesModel `tfsdk:"overrides" json:"overrides,optional"` FromList *RulesetRulesActionParametersFromListModel `tfsdk:"from_list" json:"from_list,optional"` FromValue *RulesetRulesActionParametersFromValueModel `tfsdk:"from_value" json:"from_value,optional"` - Headers *map[string]RulesetRulesActionParametersHeadersModel `tfsdk:"headers" json:"headers,computed_optional"` + Headers *map[string]RulesetRulesActionParametersHeadersModel `tfsdk:"headers" json:"headers,optional"` URI *RulesetRulesActionParametersURIModel `tfsdk:"uri" json:"uri,optional"` HostHeader types.String `tfsdk:"host_header" json:"host_header,optional"` Origin *RulesetRulesActionParametersOriginModel `tfsdk:"origin" json:"origin,optional"` @@ -252,20 +252,20 @@ type RulesetRulesActionParametersCacheReserveModel struct { } type RulesetRulesActionParametersEdgeTTLModel struct { - Default types.Int64 `tfsdk:"default" json:"default,required"` + Default types.Int64 `tfsdk:"default" json:"default,optional"` Mode types.String `tfsdk:"mode" json:"mode,required"` - StatusCodeTTL *[]*RulesetRulesActionParametersEdgeTTLStatusCodeTTLModel `tfsdk:"status_code_ttl" json:"status_code_ttl,required"` + StatusCodeTTL *[]*RulesetRulesActionParametersEdgeTTLStatusCodeTTLModel `tfsdk:"status_code_ttl" json:"status_code_ttl,optional"` } type RulesetRulesActionParametersEdgeTTLStatusCodeTTLModel struct { Value types.Int64 `tfsdk:"value" json:"value,required"` StatusCodeRange *RulesetRulesActionParametersEdgeTTLStatusCodeTTLStatusCodeRangeModel `tfsdk:"status_code_range" json:"status_code_range,optional"` - StatusCode types.Int64 `tfsdk:"status_code" json:"status_code,computed_optional"` + StatusCode types.Int64 `tfsdk:"status_code" json:"status_code,optional"` } type RulesetRulesActionParametersEdgeTTLStatusCodeTTLStatusCodeRangeModel struct { - From types.Int64 `tfsdk:"from" json:"from,required"` - To types.Int64 `tfsdk:"to" json:"to,required"` + From types.Int64 `tfsdk:"from" json:"from,optional"` + To types.Int64 `tfsdk:"to" json:"to,optional"` } type RulesetRulesActionParametersServeStaleModel struct { diff --git a/internal/services/ruleset/schema.go b/internal/services/ruleset/schema.go index ba88eb8e4f..ed10d40404 100644 --- a/internal/services/ruleset/schema.go +++ b/internal/services/ruleset/schema.go @@ -334,8 +334,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "operation": schema.StringAttribute{ - Computed: true, - Optional: true, + Required: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("remove", "set"), }, @@ -792,7 +791,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, "minimum_file_size": schema.Int64Attribute{ Description: "The minimum file size eligible for store in cache reserve.", - Optional: true, + Required: true, }, }, }, diff --git a/internal/services/snippet_rules/model.go b/internal/services/snippet_rules/model.go index 962785b04e..d37e2c2d07 100644 --- a/internal/services/snippet_rules/model.go +++ b/internal/services/snippet_rules/model.go @@ -13,8 +13,12 @@ type SnippetRulesResultEnvelope struct { } type SnippetRulesModel struct { - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Rules customfield.NestedObjectList[SnippetRulesRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Rules customfield.NestedObjectList[SnippetRulesRulesModel] `tfsdk:"rules" json:"rules,computed_optional"` + Description types.String `tfsdk:"description" json:"description,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Expression types.String `tfsdk:"expression" json:"expression,computed"` + SnippetName types.String `tfsdk:"snippet_name" json:"snippet_name,computed"` } func (m SnippetRulesModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/snippet_rules/schema.go b/internal/services/snippet_rules/schema.go index a60019819f..45ef9ddaf5 100644 --- a/internal/services/snippet_rules/schema.go +++ b/internal/services/snippet_rules/schema.go @@ -47,6 +47,19 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "description": schema.StringAttribute{ + Computed: true, + }, + "enabled": schema.BoolAttribute{ + Computed: true, + }, + "expression": schema.StringAttribute{ + Computed: true, + }, + "snippet_name": schema.StringAttribute{ + Description: "Snippet identifying name", + Computed: true, + }, }, } } diff --git a/internal/services/spectrum_application/data_source_schema.go b/internal/services/spectrum_application/data_source_schema.go index ebd26f7ac5..1e1236adda 100644 --- a/internal/services/spectrum_application/data_source_schema.go +++ b/internal/services/spectrum_application/data_source_schema.go @@ -23,11 +23,11 @@ func DataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "app_id": schema.StringAttribute{ - Description: "Identifier", + Description: "App identifier.", Required: true, }, "zone_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Zone identifier.", Required: true, }, "argo_smart_routing": schema.BoolAttribute{ diff --git a/internal/services/spectrum_application/list_data_source_schema.go b/internal/services/spectrum_application/list_data_source_schema.go index a68c07d486..d753687177 100644 --- a/internal/services/spectrum_application/list_data_source_schema.go +++ b/internal/services/spectrum_application/list_data_source_schema.go @@ -19,7 +19,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "zone_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Zone identifier.", Required: true, }, "direction": schema.StringAttribute{ diff --git a/internal/services/spectrum_application/model.go b/internal/services/spectrum_application/model.go index f83a65d60b..cbdc853322 100644 --- a/internal/services/spectrum_application/model.go +++ b/internal/services/spectrum_application/model.go @@ -14,7 +14,7 @@ type SpectrumApplicationResultEnvelope struct { } type SpectrumApplicationModel struct { - ID types.String `tfsdk:"id" json:"id,required"` + ID types.String `tfsdk:"id" json:"id,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` Protocol types.String `tfsdk:"protocol" json:"protocol,required"` DNS *SpectrumApplicationDNSModel `tfsdk:"dns" json:"dns,required"` diff --git a/internal/services/spectrum_application/schema.go b/internal/services/spectrum_application/schema.go index 5a116a07f9..4de10bded9 100644 --- a/internal/services/spectrum_application/schema.go +++ b/internal/services/spectrum_application/schema.go @@ -27,12 +27,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "Identifier", - Required: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, + Description: "App identifier.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "zone_id": schema.StringAttribute{ - Description: "Identifier", + Description: "Zone identifier.", Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, diff --git a/internal/services/stream_audio_track/data_source_model.go b/internal/services/stream_audio_track/data_source_model.go index c1b8f981ad..d0d1fba782 100644 --- a/internal/services/stream_audio_track/data_source_model.go +++ b/internal/services/stream_audio_track/data_source_model.go @@ -18,6 +18,10 @@ type StreamAudioTrackResultDataSourceEnvelope struct { type StreamAudioTrackDataSourceModel struct { AccountID types.String `tfsdk:"account_id" path:"account_id,required"` Identifier types.String `tfsdk:"identifier" path:"identifier,required"` + Default types.Bool `tfsdk:"default" json:"default,computed"` + Label types.String `tfsdk:"label" json:"label,computed"` + Status types.String `tfsdk:"status" json:"status,computed"` + UID types.String `tfsdk:"uid" json:"uid,computed"` } func (m *StreamAudioTrackDataSourceModel) toReadParams(_ context.Context) (params stream.AudioTrackGetParams, diags diag.Diagnostics) { diff --git a/internal/services/stream_audio_track/data_source_schema.go b/internal/services/stream_audio_track/data_source_schema.go index 1cb4ffa5ce..60e377f287 100644 --- a/internal/services/stream_audio_track/data_source_schema.go +++ b/internal/services/stream_audio_track/data_source_schema.go @@ -5,8 +5,10 @@ package stream_audio_track import ( "context" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) var _ datasource.DataSourceWithConfigValidators = (*StreamAudioTrackDataSource)(nil) @@ -22,6 +24,29 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "A Cloudflare-generated unique identifier for a media item.", Required: true, }, + "default": schema.BoolAttribute{ + Description: "Denotes whether the audio track will be played by default in a player.", + Computed: true, + }, + "label": schema.StringAttribute{ + Description: "A string to uniquely identify the track amongst other audio track labels for the specified video.", + Computed: true, + }, + "status": schema.StringAttribute{ + Description: "Specifies the processing status of the video.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "queued", + "ready", + "error", + ), + }, + }, + "uid": schema.StringAttribute{ + Description: "A Cloudflare-generated unique identifier for a media item.", + Computed: true, + }, }, } } diff --git a/internal/services/stream_key/data_source_model.go b/internal/services/stream_key/data_source_model.go index 2820378a63..c8d81ca0f6 100644 --- a/internal/services/stream_key/data_source_model.go +++ b/internal/services/stream_key/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/stream" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,7 +17,9 @@ type StreamKeyResultDataSourceEnvelope struct { } type StreamKeyDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Created timetypes.RFC3339 `tfsdk:"created" json:"created,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` } func (m *StreamKeyDataSourceModel) toReadParams(_ context.Context) (params stream.KeyGetParams, diags diag.Diagnostics) { diff --git a/internal/services/stream_key/data_source_schema.go b/internal/services/stream_key/data_source_schema.go index 04246990e4..227bdd0535 100644 --- a/internal/services/stream_key/data_source_schema.go +++ b/internal/services/stream_key/data_source_schema.go @@ -5,6 +5,7 @@ package stream_key import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -18,6 +19,15 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Identifier", Required: true, }, + "created": schema.StringAttribute{ + Description: "The date and time a signing key was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, }, } } diff --git a/internal/services/turnstile_widget/data_source.go b/internal/services/turnstile_widget/data_source.go index be09e213b1..da7fba37e5 100644 --- a/internal/services/turnstile_widget/data_source.go +++ b/internal/services/turnstile_widget/data_source.go @@ -64,7 +64,7 @@ func (d *TurnstileWidgetDataSource) Read(ctx context.Context, req datasource.Rea return } - env := TurnstileWidgetResultListDataSourceEnvelope{} + env := TurnstileWidgetsResultListDataSourceEnvelope{} page, err := d.client.Turnstile.Widgets.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) diff --git a/internal/services/turnstile_widget/data_source_model.go b/internal/services/turnstile_widget/data_source_model.go index 042048f62f..ee005f987b 100644 --- a/internal/services/turnstile_widget/data_source_model.go +++ b/internal/services/turnstile_widget/data_source_model.go @@ -17,10 +17,6 @@ type TurnstileWidgetResultDataSourceEnvelope struct { Result TurnstileWidgetDataSourceModel `json:"result,computed"` } -type TurnstileWidgetResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[TurnstileWidgetDataSourceModel] `json:"result,computed"` -} - type TurnstileWidgetDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` Sitekey types.String `tfsdk:"sitekey" path:"sitekey,computed_optional"` diff --git a/internal/services/waiting_room/data_source_model.go b/internal/services/waiting_room/data_source_model.go index 79b8966c43..d1c4e03f70 100644 --- a/internal/services/waiting_room/data_source_model.go +++ b/internal/services/waiting_room/data_source_model.go @@ -17,10 +17,6 @@ type WaitingRoomResultDataSourceEnvelope struct { Result WaitingRoomDataSourceModel `json:"result,computed"` } -type WaitingRoomResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WaitingRoomDataSourceModel] `json:"result,computed"` -} - type WaitingRoomDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` WaitingRoomID types.String `tfsdk:"waiting_room_id" path:"waiting_room_id,optional"` diff --git a/internal/services/waiting_room_event/data_source_model.go b/internal/services/waiting_room_event/data_source_model.go index 57bf767870..9da68e7f95 100644 --- a/internal/services/waiting_room_event/data_source_model.go +++ b/internal/services/waiting_room_event/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/waiting_rooms" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type WaitingRoomEventResultDataSourceEnvelope struct { Result WaitingRoomEventDataSourceModel `json:"result,computed"` } -type WaitingRoomEventResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WaitingRoomEventDataSourceModel] `json:"result,computed"` -} - type WaitingRoomEventDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` EventID types.String `tfsdk:"event_id" path:"event_id,optional"` diff --git a/internal/services/waiting_room_rules/data_source_model.go b/internal/services/waiting_room_rules/data_source_model.go index 4874c3b737..5d0a0efb86 100644 --- a/internal/services/waiting_room_rules/data_source_model.go +++ b/internal/services/waiting_room_rules/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/waiting_rooms" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +17,15 @@ type WaitingRoomRulesResultDataSourceEnvelope struct { } type WaitingRoomRulesDataSourceModel struct { - WaitingRoomID types.String `tfsdk:"waiting_room_id" path:"waiting_room_id,required"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + WaitingRoomID types.String `tfsdk:"waiting_room_id" path:"waiting_room_id,required"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Action types.String `tfsdk:"action" json:"action,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Expression types.String `tfsdk:"expression" json:"expression,computed"` + ID types.String `tfsdk:"id" json:"id,computed"` + LastUpdated timetypes.RFC3339 `tfsdk:"last_updated" json:"last_updated,computed" format:"date-time"` + Version types.String `tfsdk:"version" json:"version,computed"` } func (m *WaitingRoomRulesDataSourceModel) toReadParams(_ context.Context) (params waiting_rooms.RuleGetParams, diags diag.Diagnostics) { diff --git a/internal/services/waiting_room_rules/data_source_schema.go b/internal/services/waiting_room_rules/data_source_schema.go index 489e1f8230..7cb592fa0f 100644 --- a/internal/services/waiting_room_rules/data_source_schema.go +++ b/internal/services/waiting_room_rules/data_source_schema.go @@ -5,8 +5,11 @@ package waiting_room_rules import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" ) var _ datasource.DataSourceWithConfigValidators = (*WaitingRoomRulesDataSource)(nil) @@ -21,6 +24,37 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Identifier", Required: true, }, + "action": schema.StringAttribute{ + Description: "The action to take when the expression matches.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("bypass_waiting_room"), + }, + }, + "description": schema.StringAttribute{ + Description: "The description of the rule.", + Computed: true, + }, + "enabled": schema.BoolAttribute{ + Description: "When set to true, the rule is enabled.", + Computed: true, + }, + "expression": schema.StringAttribute{ + Description: "Criteria defining when there is a match for the current rule.", + Computed: true, + }, + "id": schema.StringAttribute{ + Description: "The ID of the rule.", + Computed: true, + }, + "last_updated": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "version": schema.StringAttribute{ + Description: "The version of the rule.", + Computed: true, + }, }, } } diff --git a/internal/services/waiting_room_rules/model.go b/internal/services/waiting_room_rules/model.go index 67f6bdd077..ac964250a0 100644 --- a/internal/services/waiting_room_rules/model.go +++ b/internal/services/waiting_room_rules/model.go @@ -4,6 +4,7 @@ package waiting_room_rules import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -12,10 +13,16 @@ type WaitingRoomRulesResultEnvelope struct { } type WaitingRoomRulesModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` WaitingRoomID types.String `tfsdk:"waiting_room_id" path:"waiting_room_id,required"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` Rules *[]*WaitingRoomRulesRulesModel `tfsdk:"rules" json:"rules,required"` + Action types.String `tfsdk:"action" json:"action,computed"` + Description types.String `tfsdk:"description" json:"description,computed"` + Enabled types.Bool `tfsdk:"enabled" json:"enabled,computed"` + Expression types.String `tfsdk:"expression" json:"expression,computed"` + LastUpdated timetypes.RFC3339 `tfsdk:"last_updated" json:"last_updated,computed" format:"date-time"` + Version types.String `tfsdk:"version" json:"version,computed"` } func (m WaitingRoomRulesModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/waiting_room_rules/resource.go b/internal/services/waiting_room_rules/resource.go index 0111d31a6b..55f003528f 100644 --- a/internal/services/waiting_room_rules/resource.go +++ b/internal/services/waiting_room_rules/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/cloudflare-go/v4/waiting_rooms" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*WaitingRoomRulesResource)(nil) var _ resource.ResourceWithModifyPlan = (*WaitingRoomRulesResource)(nil) +var _ resource.ResourceWithImportState = (*WaitingRoomRulesResource)(nil) func NewResource() resource.Resource { return &WaitingRoomRulesResource{} @@ -119,7 +122,7 @@ func (r *WaitingRoomRulesResource) Update(ctx context.Context, req resource.Upda env := WaitingRoomRulesResultEnvelope{data.Rules} _, err = r.client.WaitingRooms.Rules.Update( ctx, - data.WaitingRoomID.ValueString(), + data.ID.ValueString(), waiting_rooms.RuleUpdateParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -155,7 +158,7 @@ func (r *WaitingRoomRulesResource) Read(ctx context.Context, req resource.ReadRe env := WaitingRoomRulesResultEnvelope{data.Rules} _, err := r.client.WaitingRooms.Rules.Get( ctx, - data.WaitingRoomID.ValueString(), + data.ID.ValueString(), waiting_rooms.RuleGetParams{ ZoneID: cloudflare.F(data.ZoneID.ValueString()), }, @@ -210,6 +213,51 @@ func (r *WaitingRoomRulesResource) Delete(ctx context.Context, req resource.Dele resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } +func (r *WaitingRoomRulesResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *WaitingRoomRulesModel = new(WaitingRoomRulesModel) + + path_zone_id := "" + path_waiting_room_id := "" + diags := importpath.ParseImportID( + req.ID, + "/", + &path_zone_id, + &path_waiting_room_id, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.ZoneID = types.StringValue(path_zone_id) + data.WaitingRoomID = types.StringValue(path_waiting_room_id) + + res := new(http.Response) + env := WaitingRoomRulesResultEnvelope{data.Rules} + _, err := r.client.WaitingRooms.Rules.Get( + ctx, + path_waiting_room_id, + waiting_rooms.RuleGetParams{ + ZoneID: cloudflare.F(path_zone_id), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data.Rules = env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *WaitingRoomRulesResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { } diff --git a/internal/services/waiting_room_rules/schema.go b/internal/services/waiting_room_rules/schema.go index 42b406f9c8..183d61bae1 100644 --- a/internal/services/waiting_room_rules/schema.go +++ b/internal/services/waiting_room_rules/schema.go @@ -5,6 +5,7 @@ package waiting_room_rules import ( "context" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -21,6 +22,11 @@ var _ resource.ResourceWithConfigValidators = (*WaitingRoomRulesResource)(nil) func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of the rule.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, + }, "waiting_room_id": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, @@ -30,11 +36,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, - "rule_id": schema.StringAttribute{ - Description: "The ID of the rule.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, - }, "rules": schema.ListNestedAttribute{ Required: true, NestedObject: schema.NestedAttributeObject{ @@ -66,6 +67,35 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "action": schema.StringAttribute{ + Description: "The action to take when the expression matches.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("bypass_waiting_room"), + }, + }, + "description": schema.StringAttribute{ + Description: "The description of the rule.", + Computed: true, + Default: stringdefault.StaticString(""), + }, + "enabled": schema.BoolAttribute{ + Description: "When set to true, the rule is enabled.", + Computed: true, + Default: booldefault.StaticBool(true), + }, + "expression": schema.StringAttribute{ + Description: "Criteria defining when there is a match for the current rule.", + Computed: true, + }, + "last_updated": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "version": schema.StringAttribute{ + Description: "The version of the rule.", + Computed: true, + }, }, } } diff --git a/internal/services/web3_hostname/data_source_model.go b/internal/services/web3_hostname/data_source_model.go index 949541b3e6..d1a53db2e2 100644 --- a/internal/services/web3_hostname/data_source_model.go +++ b/internal/services/web3_hostname/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/web3" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type Web3HostnameResultDataSourceEnvelope struct { Result Web3HostnameDataSourceModel `json:"result,computed"` } -type Web3HostnameResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[Web3HostnameDataSourceModel] `json:"result,computed"` -} - type Web3HostnameDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` Identifier types.String `tfsdk:"identifier" path:"identifier,optional"` diff --git a/internal/services/web_analytics_site/data_source.go b/internal/services/web_analytics_site/data_source.go index 7cc8392fb0..7a22a0bc39 100644 --- a/internal/services/web_analytics_site/data_source.go +++ b/internal/services/web_analytics_site/data_source.go @@ -64,7 +64,7 @@ func (d *WebAnalyticsSiteDataSource) Read(ctx context.Context, req datasource.Re return } - env := WebAnalyticsSiteResultListDataSourceEnvelope{} + env := WebAnalyticsSitesResultListDataSourceEnvelope{} page, err := d.client.RUM.SiteInfo.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *WebAnalyticsSiteDataSource) Read(ctx context.Context, req datasource.Re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.SiteID = ts[0].SiteID + data.SiteID = ts[0].SiteTag } params, diags := data.toReadParams(ctx) diff --git a/internal/services/web_analytics_site/data_source_model.go b/internal/services/web_analytics_site/data_source_model.go index 1f76bf23d8..ab13aec56d 100644 --- a/internal/services/web_analytics_site/data_source_model.go +++ b/internal/services/web_analytics_site/data_source_model.go @@ -17,10 +17,6 @@ type WebAnalyticsSiteResultDataSourceEnvelope struct { Result WebAnalyticsSiteDataSourceModel `json:"result,computed"` } -type WebAnalyticsSiteResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WebAnalyticsSiteDataSourceModel] `json:"result,computed"` -} - type WebAnalyticsSiteDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` SiteID types.String `tfsdk:"site_id" path:"site_id,optional"` diff --git a/internal/services/workers_custom_domain/data_source.go b/internal/services/workers_custom_domain/data_source.go index 3a707eb6ba..355e604235 100644 --- a/internal/services/workers_custom_domain/data_source.go +++ b/internal/services/workers_custom_domain/data_source.go @@ -64,7 +64,7 @@ func (d *WorkersCustomDomainDataSource) Read(ctx context.Context, req datasource return } - env := WorkersCustomDomainResultListDataSourceEnvelope{} + env := WorkersCustomDomainsResultListDataSourceEnvelope{} page, err := d.client.Workers.Domains.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *WorkersCustomDomainDataSource) Read(ctx context.Context, req datasource } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.DomainID = ts[0].DomainID + data.DomainID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/workers_custom_domain/data_source_model.go b/internal/services/workers_custom_domain/data_source_model.go index 330bc47088..aff9a21588 100644 --- a/internal/services/workers_custom_domain/data_source_model.go +++ b/internal/services/workers_custom_domain/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/workers" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type WorkersCustomDomainResultDataSourceEnvelope struct { Result WorkersCustomDomainDataSourceModel `json:"result,computed"` } -type WorkersCustomDomainResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WorkersCustomDomainDataSourceModel] `json:"result,computed"` -} - type WorkersCustomDomainDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DomainID types.String `tfsdk:"domain_id" path:"domain_id,optional"` diff --git a/internal/services/workers_for_platforms_dispatch_namespace/data_source_model.go b/internal/services/workers_for_platforms_dispatch_namespace/data_source_model.go index 1b7c904553..7eb228ef65 100644 --- a/internal/services/workers_for_platforms_dispatch_namespace/data_source_model.go +++ b/internal/services/workers_for_platforms_dispatch_namespace/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/workers_for_platforms" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type WorkersForPlatformsDispatchNamespaceResultDataSourceEnvelope struct { Result WorkersForPlatformsDispatchNamespaceDataSourceModel `json:"result,computed"` } -type WorkersForPlatformsDispatchNamespaceResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WorkersForPlatformsDispatchNamespaceDataSourceModel] `json:"result,computed"` -} - type WorkersForPlatformsDispatchNamespaceDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DispatchNamespace types.String `tfsdk:"dispatch_namespace" path:"dispatch_namespace,optional"` diff --git a/internal/services/workers_kv_namespace/data_source.go b/internal/services/workers_kv_namespace/data_source.go index cf6645dfab..48e533868b 100644 --- a/internal/services/workers_kv_namespace/data_source.go +++ b/internal/services/workers_kv_namespace/data_source.go @@ -64,7 +64,7 @@ func (d *WorkersKVNamespaceDataSource) Read(ctx context.Context, req datasource. return } - env := WorkersKVNamespaceResultListDataSourceEnvelope{} + env := WorkersKVNamespacesResultListDataSourceEnvelope{} page, err := d.client.KV.Namespaces.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *WorkersKVNamespaceDataSource) Read(ctx context.Context, req datasource. } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.NamespaceID = ts[0].NamespaceID + data.NamespaceID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/workers_kv_namespace/data_source_model.go b/internal/services/workers_kv_namespace/data_source_model.go index 377cd250b4..42c33f11a1 100644 --- a/internal/services/workers_kv_namespace/data_source_model.go +++ b/internal/services/workers_kv_namespace/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/kv" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type WorkersKVNamespaceResultDataSourceEnvelope struct { Result WorkersKVNamespaceDataSourceModel `json:"result,computed"` } -type WorkersKVNamespaceResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WorkersKVNamespaceDataSourceModel] `json:"result,computed"` -} - type WorkersKVNamespaceDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` NamespaceID types.String `tfsdk:"namespace_id" path:"namespace_id,optional"` diff --git a/internal/services/workers_route/data_source.go b/internal/services/workers_route/data_source.go new file mode 100644 index 0000000000..83d3b10876 --- /dev/null +++ b/internal/services/workers_route/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type WorkersRouteDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*WorkersRouteDataSource)(nil) + +func NewWorkersRouteDataSource() datasource.DataSource { + return &WorkersRouteDataSource{} +} + +func (d *WorkersRouteDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_workers_route" +} + +func (d *WorkersRouteDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *WorkersRouteDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *WorkersRouteDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := WorkersRouteResultDataSourceEnvelope{*data} + _, err := d.client.Workers.Routes.Get( + ctx, + data.RouteID.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/workers_route/data_source_model.go b/internal/services/workers_route/data_source_model.go new file mode 100644 index 0000000000..828fbf3762 --- /dev/null +++ b/internal/services/workers_route/data_source_model.go @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/workers" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type WorkersRouteResultDataSourceEnvelope struct { + Result WorkersRouteDataSourceModel `json:"result,computed"` +} + +type WorkersRouteDataSourceModel struct { + RouteID types.String `tfsdk:"route_id" path:"route_id,required"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + ID types.String `tfsdk:"id" json:"id,computed"` + Pattern types.String `tfsdk:"pattern" json:"pattern,computed"` + Script types.String `tfsdk:"script" json:"script,computed"` +} + +func (m *WorkersRouteDataSourceModel) toReadParams(_ context.Context) (params workers.RouteGetParams, diags diag.Diagnostics) { + params = workers.RouteGetParams{ + ZoneID: cloudflare.F(m.ZoneID.ValueString()), + } + + return +} diff --git a/internal/services/workers_route/data_source_schema.go b/internal/services/workers_route/data_source_schema.go new file mode 100644 index 0000000000..f63b2b1f86 --- /dev/null +++ b/internal/services/workers_route/data_source_schema.go @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +var _ datasource.DataSourceWithConfigValidators = (*WorkersRouteDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "route_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "zone_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, + "pattern": schema.StringAttribute{ + Computed: true, + }, + "script": schema.StringAttribute{ + Description: "Name of the script, used in URLs and route configuration.", + Computed: true, + }, + }, + } +} + +func (d *WorkersRouteDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *WorkersRouteDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/workers_route/data_source_schema_test.go b/internal/services/workers_route/data_source_schema_test.go new file mode 100644 index 0000000000..01265f600c --- /dev/null +++ b/internal/services/workers_route/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_route" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestWorkersRouteDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*workers_route.WorkersRouteDataSourceModel)(nil) + schema := workers_route.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/workers_route/list_data_source.go b/internal/services/workers_route/list_data_source.go new file mode 100644 index 0000000000..eeb697992d --- /dev/null +++ b/internal/services/workers_route/list_data_source.go @@ -0,0 +1,100 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + "fmt" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type WorkersRoutesDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*WorkersRoutesDataSource)(nil) + +func NewWorkersRoutesDataSource() datasource.DataSource { + return &WorkersRoutesDataSource{} +} + +func (d *WorkersRoutesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_workers_routes" +} + +func (d *WorkersRoutesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *WorkersRoutesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *WorkersRoutesDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toListParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + env := WorkersRoutesResultListDataSourceEnvelope{} + maxItems := int(data.MaxItems.ValueInt64()) + acc := []attr.Value{} + if maxItems <= 0 { + maxItems = 1000 + } + page, err := d.client.Workers.Routes.List(ctx, params) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + for page != nil && len(page.Result) > 0 { + bytes := []byte(page.JSON.RawJSON()) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to unmarshal http request", err.Error()) + return + } + acc = append(acc, env.Result.Elements()...) + if len(acc) >= maxItems { + break + } + page, err = page.GetNextPage() + if err != nil { + resp.Diagnostics.AddError("failed to fetch next page", err.Error()) + return + } + } + + acc = acc[:min(len(acc), maxItems)] + result, diags := customfield.NewObjectListFromAttributes[WorkersRoutesResultDataSourceModel](ctx, acc) + resp.Diagnostics.Append(diags...) + data.Result = result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/workers_route/list_data_source_model.go b/internal/services/workers_route/list_data_source_model.go new file mode 100644 index 0000000000..fc47475ddb --- /dev/null +++ b/internal/services/workers_route/list_data_source_model.go @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/workers" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type WorkersRoutesResultListDataSourceEnvelope struct { + Result customfield.NestedObjectList[WorkersRoutesResultDataSourceModel] `json:"result,computed"` +} + +type WorkersRoutesDataSourceModel struct { + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + MaxItems types.Int64 `tfsdk:"max_items"` + Result customfield.NestedObjectList[WorkersRoutesResultDataSourceModel] `tfsdk:"result"` +} + +func (m *WorkersRoutesDataSourceModel) toListParams(_ context.Context) (params workers.RouteListParams, diags diag.Diagnostics) { + params = workers.RouteListParams{ + ZoneID: cloudflare.F(m.ZoneID.ValueString()), + } + + return +} + +type WorkersRoutesResultDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` + Pattern types.String `tfsdk:"pattern" json:"pattern,computed"` + Script types.String `tfsdk:"script" json:"script,computed"` +} diff --git a/internal/services/workers_route/list_data_source_schema.go b/internal/services/workers_route/list_data_source_schema.go new file mode 100644 index 0000000000..391753faca --- /dev/null +++ b/internal/services/workers_route/list_data_source_schema.go @@ -0,0 +1,61 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ datasource.DataSourceWithConfigValidators = (*WorkersRoutesDataSource)(nil) + +func ListDataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "zone_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + }, + "max_items": schema.Int64Attribute{ + Description: "Max items to fetch, default: 1000", + Optional: true, + Validators: []validator.Int64{ + int64validator.AtLeast(0), + }, + }, + "result": schema.ListNestedAttribute{ + Description: "The items returned by the data source", + Computed: true, + CustomType: customfield.NewNestedObjectListType[WorkersRoutesResultDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, + "pattern": schema.StringAttribute{ + Computed: true, + }, + "script": schema.StringAttribute{ + Description: "Name of the script, used in URLs and route configuration.", + Computed: true, + }, + }, + }, + }, + }, + } +} + +func (d *WorkersRoutesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = ListDataSourceSchema(ctx) +} + +func (d *WorkersRoutesDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/workers_route/list_data_source_schema_test.go b/internal/services/workers_route/list_data_source_schema_test.go new file mode 100644 index 0000000000..fe75cf11a9 --- /dev/null +++ b/internal/services/workers_route/list_data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_route" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestWorkersRoutesDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*workers_route.WorkersRoutesDataSourceModel)(nil) + schema := workers_route.ListDataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/workers_route/migrations.go b/internal/services/workers_route/migrations.go new file mode 100644 index 0000000000..fd745788a6 --- /dev/null +++ b/internal/services/workers_route/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*WorkersRouteResource)(nil) + +func (r *WorkersRouteResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/workers_route/model.go b/internal/services/workers_route/model.go new file mode 100644 index 0000000000..52c1282d26 --- /dev/null +++ b/internal/services/workers_route/model.go @@ -0,0 +1,42 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type WorkersRouteResultEnvelope struct { + Result WorkersRouteModel `json:"result"` +} + +type WorkersRouteModel struct { + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + RouteID types.String `tfsdk:"route_id" path:"route_id,optional"` + Pattern types.String `tfsdk:"pattern" json:"pattern,required"` + Script types.String `tfsdk:"script" json:"script,optional"` + ID types.String `tfsdk:"id" json:"id,computed"` + Success types.Bool `tfsdk:"success" json:"success,computed"` + Errors customfield.NestedObjectList[WorkersRouteErrorsModel] `tfsdk:"errors" json:"errors,computed"` + Messages customfield.NestedObjectList[WorkersRouteMessagesModel] `tfsdk:"messages" json:"messages,computed"` +} + +func (m WorkersRouteModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m WorkersRouteModel) MarshalJSONForUpdate(state WorkersRouteModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type WorkersRouteErrorsModel struct { + Code types.Int64 `tfsdk:"code" json:"code,computed"` + Message types.String `tfsdk:"message" json:"message,computed"` +} + +type WorkersRouteMessagesModel struct { + Code types.Int64 `tfsdk:"code" json:"code,computed"` + Message types.String `tfsdk:"message" json:"message,computed"` +} diff --git a/internal/services/workers_route/resource.go b/internal/services/workers_route/resource.go new file mode 100644 index 0000000000..e46829c23e --- /dev/null +++ b/internal/services/workers_route/resource.go @@ -0,0 +1,209 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/workers" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*WorkersRouteResource)(nil) +var _ resource.ResourceWithModifyPlan = (*WorkersRouteResource)(nil) + +func NewResource() resource.Resource { + return &WorkersRouteResource{} +} + +// WorkersRouteResource defines the resource implementation. +type WorkersRouteResource struct { + client *cloudflare.Client +} + +func (r *WorkersRouteResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_workers_route" +} + +func (r *WorkersRouteResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *WorkersRouteResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *WorkersRouteModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + _, err = r.client.Workers.Routes.New( + ctx, + workers.RouteNewParams{ + ZoneID: cloudflare.F(data.ZoneID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &data) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *WorkersRouteResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *WorkersRouteModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *WorkersRouteModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := WorkersRouteResultEnvelope{*data} + _, err = r.client.Workers.Routes.Update( + ctx, + data.RouteID.ValueString(), + workers.RouteUpdateParams{ + ZoneID: cloudflare.F(data.ZoneID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *WorkersRouteResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *WorkersRouteModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := WorkersRouteResultEnvelope{*data} + _, err := r.client.Workers.Routes.Get( + ctx, + data.RouteID.ValueString(), + workers.RouteGetParams{ + ZoneID: cloudflare.F(data.ZoneID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *WorkersRouteResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data *WorkersRouteModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + _, err := r.client.Workers.Routes.Delete( + ctx, + data.RouteID.ValueString(), + workers.RouteDeleteParams{ + ZoneID: cloudflare.F(data.ZoneID.ValueString()), + }, + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *WorkersRouteResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, _ *resource.ModifyPlanResponse) { + +} diff --git a/internal/services/workers_route/resource_schema_test.go b/internal/services/workers_route/resource_schema_test.go new file mode 100644 index 0000000000..3400ad9290 --- /dev/null +++ b/internal/services/workers_route/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_route" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestWorkersRouteModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*workers_route.WorkersRouteModel)(nil) + schema := workers_route.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/workers_route/schema.go b/internal/services/workers_route/schema.go new file mode 100644 index 0000000000..cedbb2972c --- /dev/null +++ b/internal/services/workers_route/schema.go @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package workers_route + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +var _ resource.ResourceWithConfigValidators = (*WorkersRouteResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "zone_id": schema.StringAttribute{ + Description: "Identifier", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "route_id": schema.StringAttribute{ + Description: "Identifier", + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "pattern": schema.StringAttribute{ + Required: true, + }, + "script": schema.StringAttribute{ + Description: "Name of the script, used in URLs and route configuration.", + Optional: true, + }, + "id": schema.StringAttribute{ + Description: "Identifier", + Computed: true, + }, + "success": schema.BoolAttribute{ + Description: "Whether the API call was successful", + Computed: true, + }, + "errors": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[WorkersRouteErrorsModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "code": schema.Int64Attribute{ + Computed: true, + Validators: []validator.Int64{ + int64validator.AtLeast(1000), + }, + }, + "message": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + "messages": schema.ListNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectListType[WorkersRouteMessagesModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "code": schema.Int64Attribute{ + Computed: true, + Validators: []validator.Int64{ + int64validator.AtLeast(1000), + }, + }, + "message": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + } +} + +func (r *WorkersRouteResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *WorkersRouteResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/workers_script/resource_schema_test.go b/internal/services/workers_script/resource_schema_test.go index cc6245e771..2a5696a9a1 100644 --- a/internal/services/workers_script/resource_schema_test.go +++ b/internal/services/workers_script/resource_schema_test.go @@ -3,17 +3,10 @@ package workers_script_test import ( - "context" "testing" - - "github.com/cloudflare/terraform-provider-cloudflare/internal/services/workers_script" - "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" ) func TestWorkersScriptModelSchemaParity(t *testing.T) { - t.Parallel() - model := (*workers_script.WorkersScriptModel)(nil) - schema := workers_script.ResourceSchema(context.TODO()) - errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) - errs.Report(t) + // TODO: the workers resource is a special case and the validation is largely + // irrelevant here given we move it all around to make it work. } diff --git a/internal/services/workers_secret/data_source_model.go b/internal/services/workers_secret/data_source_model.go index 4f748e7f6e..8493b223f1 100644 --- a/internal/services/workers_secret/data_source_model.go +++ b/internal/services/workers_secret/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/workers_for_platforms" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,10 +15,6 @@ type WorkersSecretResultDataSourceEnvelope struct { Result WorkersSecretDataSourceModel `json:"result,computed"` } -type WorkersSecretResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[WorkersSecretDataSourceModel] `json:"result,computed"` -} - type WorkersSecretDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` SecretName types.String `tfsdk:"secret_name" path:"secret_name,optional"` diff --git a/internal/services/zero_trust_access_application/data_source.go b/internal/services/zero_trust_access_application/data_source.go index e5b35a8d64..9a47e3a817 100644 --- a/internal/services/zero_trust_access_application/data_source.go +++ b/internal/services/zero_trust_access_application/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustAccessApplicationDataSource) Read(ctx context.Context, req dat return } - env := ZeroTrustAccessApplicationResultListDataSourceEnvelope{} + env := ZeroTrustAccessApplicationsResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Access.Applications.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustAccessApplicationDataSource) Read(ctx context.Context, req dat } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.AppID = ts[0].AppID + data.AppID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_access_application/data_source_model.go b/internal/services/zero_trust_access_application/data_source_model.go index d5c0c6ab6a..1bfe834e57 100644 --- a/internal/services/zero_trust_access_application/data_source_model.go +++ b/internal/services/zero_trust_access_application/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustAccessApplicationResultDataSourceEnvelope struct { Result ZeroTrustAccessApplicationDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessApplicationResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessApplicationDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessApplicationDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` AppID types.String `tfsdk:"app_id" path:"app_id,optional"` @@ -179,6 +175,7 @@ type ZeroTrustAccessApplicationPoliciesExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -254,6 +251,10 @@ type ZeroTrustAccessApplicationPoliciesExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationPoliciesExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationPoliciesExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -294,6 +295,7 @@ type ZeroTrustAccessApplicationPoliciesIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -369,6 +371,10 @@ type ZeroTrustAccessApplicationPoliciesIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationPoliciesIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationPoliciesIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -409,6 +415,7 @@ type ZeroTrustAccessApplicationPoliciesRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -484,6 +491,10 @@ type ZeroTrustAccessApplicationPoliciesRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationPoliciesRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationPoliciesRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -553,8 +564,13 @@ type ZeroTrustAccessApplicationSaaSAppCustomAttributesDataSourceModel struct { } type ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceDataSourceModel struct { - Name types.String `tfsdk:"name" json:"name,computed"` - NameByIdP customfield.Map[types.String] `tfsdk:"name_by_idp" json:"name_by_idp,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + NameByIdP customfield.NestedObjectList[ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPDataSourceModel] `tfsdk:"name_by_idp" json:"name_by_idp,computed"` +} + +type ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPDataSourceModel struct { + IdPID types.String `tfsdk:"idp_id" json:"idp_id,computed"` + SourceName types.String `tfsdk:"source_name" json:"source_name,computed"` } type ZeroTrustAccessApplicationSaaSAppCustomClaimsDataSourceModel struct { diff --git a/internal/services/zero_trust_access_application/data_source_schema.go b/internal/services/zero_trust_access_application/data_source_schema.go index ece2092151..155ce0253c 100644 --- a/internal/services/zero_trust_access_application/data_source_schema.go +++ b/internal/services/zero_trust_access_application/data_source_schema.go @@ -547,6 +547,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesExcludeIPListDataSourceModel](ctx), @@ -793,6 +803,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesIncludeIPListDataSourceModel](ctx), @@ -1055,6 +1075,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesRequireIPListDataSourceModel](ctx), @@ -1214,11 +1244,22 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "The name of the IdP attribute.", Computed: true, }, - "name_by_idp": schema.MapAttribute{ + "name_by_idp": schema.ListNestedAttribute{ Description: "A mapping from IdP ID to attribute name.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "idp_id": schema.StringAttribute{ + Description: "The UID of the IdP.", + Computed: true, + }, + "source_name": schema.StringAttribute{ + Description: "The name of the IdP provided attribute.", + Computed: true, + }, + }, + }, }, }, }, diff --git a/internal/services/zero_trust_access_application/list_data_source_model.go b/internal/services/zero_trust_access_application/list_data_source_model.go index 3be683ad3d..106298c446 100644 --- a/internal/services/zero_trust_access_application/list_data_source_model.go +++ b/internal/services/zero_trust_access_application/list_data_source_model.go @@ -157,6 +157,7 @@ type ZeroTrustAccessApplicationsPoliciesExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -232,6 +233,10 @@ type ZeroTrustAccessApplicationsPoliciesExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationsPoliciesExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationsPoliciesExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -272,6 +277,7 @@ type ZeroTrustAccessApplicationsPoliciesIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -347,6 +353,10 @@ type ZeroTrustAccessApplicationsPoliciesIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationsPoliciesIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationsPoliciesIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -387,6 +397,7 @@ type ZeroTrustAccessApplicationsPoliciesRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessApplicationsPoliciesRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -462,6 +473,10 @@ type ZeroTrustAccessApplicationsPoliciesRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessApplicationsPoliciesRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessApplicationsPoliciesRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -567,8 +582,13 @@ type ZeroTrustAccessApplicationsSaaSAppCustomAttributesDataSourceModel struct { } type ZeroTrustAccessApplicationsSaaSAppCustomAttributesSourceDataSourceModel struct { - Name types.String `tfsdk:"name" json:"name,computed"` - NameByIdP customfield.Map[types.String] `tfsdk:"name_by_idp" json:"name_by_idp,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + NameByIdP customfield.NestedObjectList[ZeroTrustAccessApplicationsSaaSAppCustomAttributesSourceNameByIdPDataSourceModel] `tfsdk:"name_by_idp" json:"name_by_idp,computed"` +} + +type ZeroTrustAccessApplicationsSaaSAppCustomAttributesSourceNameByIdPDataSourceModel struct { + IdPID types.String `tfsdk:"idp_id" json:"idp_id,computed"` + SourceName types.String `tfsdk:"source_name" json:"source_name,computed"` } type ZeroTrustAccessApplicationsSaaSAppCustomClaimsDataSourceModel struct { diff --git a/internal/services/zero_trust_access_application/list_data_source_schema.go b/internal/services/zero_trust_access_application/list_data_source_schema.go index ef34a34a55..6f1cba7ae3 100644 --- a/internal/services/zero_trust_access_application/list_data_source_schema.go +++ b/internal/services/zero_trust_access_application/list_data_source_schema.go @@ -481,6 +481,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesExcludeIPListDataSourceModel](ctx), @@ -727,6 +737,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesIncludeIPListDataSourceModel](ctx), @@ -989,6 +1009,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationsPoliciesRequireIPListDataSourceModel](ctx), @@ -1307,11 +1337,22 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "The name of the IdP attribute.", Computed: true, }, - "name_by_idp": schema.MapAttribute{ + "name_by_idp": schema.ListNestedAttribute{ Description: "A mapping from IdP ID to attribute name.", Computed: true, - CustomType: customfield.NewMapType[types.String](ctx), - ElementType: types.StringType, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationsSaaSAppCustomAttributesSourceNameByIdPDataSourceModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "idp_id": schema.StringAttribute{ + Description: "The UID of the IdP.", + Computed: true, + }, + "source_name": schema.StringAttribute{ + Description: "The name of the IdP provided attribute.", + Computed: true, + }, + }, + }, }, }, }, diff --git a/internal/services/zero_trust_access_application/model.go b/internal/services/zero_trust_access_application/model.go index fc2e98d1e5..a29d03584c 100644 --- a/internal/services/zero_trust_access_application/model.go +++ b/internal/services/zero_trust_access_application/model.go @@ -126,6 +126,7 @@ type ZeroTrustAccessApplicationPoliciesIncludeModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesIncludeOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -201,6 +202,10 @@ type ZeroTrustAccessApplicationPoliciesIncludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessApplicationPoliciesIncludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessApplicationPoliciesIncludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -250,6 +255,7 @@ type ZeroTrustAccessApplicationPoliciesExcludeModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesExcludeOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -325,6 +331,10 @@ type ZeroTrustAccessApplicationPoliciesExcludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessApplicationPoliciesExcludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessApplicationPoliciesExcludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -365,6 +375,7 @@ type ZeroTrustAccessApplicationPoliciesRequireModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessApplicationPoliciesRequireOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -440,6 +451,10 @@ type ZeroTrustAccessApplicationPoliciesRequireGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessApplicationPoliciesRequireLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessApplicationPoliciesRequireIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -500,8 +515,13 @@ type ZeroTrustAccessApplicationSaaSAppCustomAttributesModel struct { } type ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceModel struct { - Name types.String `tfsdk:"name" json:"name,optional"` - NameByIdP *map[string]types.String `tfsdk:"name_by_idp" json:"name_by_idp,optional"` + Name types.String `tfsdk:"name" json:"name,optional"` + NameByIdP customfield.NestedObjectList[ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPModel] `tfsdk:"name_by_idp" json:"name_by_idp,computed_optional"` +} + +type ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPModel struct { + IdPID types.String `tfsdk:"idp_id" json:"idp_id,optional"` + SourceName types.String `tfsdk:"source_name" json:"source_name,optional"` } type ZeroTrustAccessApplicationSaaSAppCustomClaimsModel struct { diff --git a/internal/services/zero_trust_access_application/schema.go b/internal/services/zero_trust_access_application/schema.go index 3241c4d4d3..c554dc2364 100644 --- a/internal/services/zero_trust_access_application/schema.go +++ b/internal/services/zero_trust_access_application/schema.go @@ -532,6 +532,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesIncludeLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, @@ -823,6 +834,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesExcludeLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, @@ -1085,6 +1107,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessApplicationPoliciesRequireLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, @@ -1217,10 +1250,23 @@ func ResourceSchema(ctx context.Context) schema.Schema { Description: "The name of the IdP attribute.", Optional: true, }, - "name_by_idp": schema.MapAttribute{ + "name_by_idp": schema.ListNestedAttribute{ Description: "A mapping from IdP ID to attribute name.", + Computed: true, Optional: true, - ElementType: types.StringType, + CustomType: customfield.NewNestedObjectListType[ZeroTrustAccessApplicationSaaSAppCustomAttributesSourceNameByIdPModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "idp_id": schema.StringAttribute{ + Description: "The UID of the IdP.", + Optional: true, + }, + "source_name": schema.StringAttribute{ + Description: "The name of the IdP provided attribute.", + Optional: true, + }, + }, + }, }, }, }, diff --git a/internal/services/zero_trust_access_custom_page/data_source_model.go b/internal/services/zero_trust_access_custom_page/data_source_model.go index 7c46cd8a3c..d5f1ae180f 100644 --- a/internal/services/zero_trust_access_custom_page/data_source_model.go +++ b/internal/services/zero_trust_access_custom_page/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustAccessCustomPageResultDataSourceEnvelope struct { Result ZeroTrustAccessCustomPageDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessCustomPageResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessCustomPageDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessCustomPageDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CustomPageID types.String `tfsdk:"custom_page_id" path:"custom_page_id,optional"` diff --git a/internal/services/zero_trust_access_group/data_source.go b/internal/services/zero_trust_access_group/data_source.go index 969b20b67e..ca4e4d80b7 100644 --- a/internal/services/zero_trust_access_group/data_source.go +++ b/internal/services/zero_trust_access_group/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustAccessGroupDataSource) Read(ctx context.Context, req datasourc return } - env := ZeroTrustAccessGroupResultListDataSourceEnvelope{} + env := ZeroTrustAccessGroupsResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Access.Groups.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustAccessGroupDataSource) Read(ctx context.Context, req datasourc } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.GroupID = ts[0].GroupID + data.GroupID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_access_group/data_source_model.go b/internal/services/zero_trust_access_group/data_source_model.go index 3fe76304ba..5c398b6855 100644 --- a/internal/services/zero_trust_access_group/data_source_model.go +++ b/internal/services/zero_trust_access_group/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustAccessGroupResultDataSourceEnvelope struct { Result ZeroTrustAccessGroupDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessGroupResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessGroupDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessGroupDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` GroupID types.String `tfsdk:"group_id" path:"group_id,optional"` @@ -84,6 +80,7 @@ type ZeroTrustAccessGroupExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -159,6 +156,10 @@ type ZeroTrustAccessGroupExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -199,6 +200,7 @@ type ZeroTrustAccessGroupIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -274,6 +276,10 @@ type ZeroTrustAccessGroupIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -314,6 +320,7 @@ type ZeroTrustAccessGroupIsDefaultDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupIsDefaultExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupIsDefaultGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupIsDefaultGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupIsDefaultLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupIsDefaultIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupIsDefaultIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupIsDefaultOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -389,6 +396,10 @@ type ZeroTrustAccessGroupIsDefaultGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupIsDefaultLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupIsDefaultIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -429,6 +440,7 @@ type ZeroTrustAccessGroupRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -504,6 +516,10 @@ type ZeroTrustAccessGroupRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } diff --git a/internal/services/zero_trust_access_group/data_source_schema.go b/internal/services/zero_trust_access_group/data_source_schema.go index 8c00856ac2..360465d34d 100644 --- a/internal/services/zero_trust_access_group/data_source_schema.go +++ b/internal/services/zero_trust_access_group/data_source_schema.go @@ -227,6 +227,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupExcludeIPListDataSourceModel](ctx), @@ -473,6 +483,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupIncludeIPListDataSourceModel](ctx), @@ -719,6 +739,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupIsDefaultLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupIsDefaultIPListDataSourceModel](ctx), @@ -965,6 +995,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupRequireIPListDataSourceModel](ctx), diff --git a/internal/services/zero_trust_access_group/list_data_source_model.go b/internal/services/zero_trust_access_group/list_data_source_model.go index b35b146e02..2aa0e9d796 100644 --- a/internal/services/zero_trust_access_group/list_data_source_model.go +++ b/internal/services/zero_trust_access_group/list_data_source_model.go @@ -73,6 +73,7 @@ type ZeroTrustAccessGroupsExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupsExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupsExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupsExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupsExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupsExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupsExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupsExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -148,6 +149,10 @@ type ZeroTrustAccessGroupsExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupsExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupsExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -188,6 +193,7 @@ type ZeroTrustAccessGroupsIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupsIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupsIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupsIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupsIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupsIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupsIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupsIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -263,6 +269,10 @@ type ZeroTrustAccessGroupsIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupsIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupsIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -303,6 +313,7 @@ type ZeroTrustAccessGroupsIsDefaultDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupsIsDefaultOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -378,6 +389,10 @@ type ZeroTrustAccessGroupsIsDefaultGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupsIsDefaultLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupsIsDefaultIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -418,6 +433,7 @@ type ZeroTrustAccessGroupsRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupsRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupsRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessGroupsRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupsRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessGroupsRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessGroupsRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessGroupsRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -493,6 +509,10 @@ type ZeroTrustAccessGroupsRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessGroupsRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessGroupsRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } diff --git a/internal/services/zero_trust_access_group/list_data_source_schema.go b/internal/services/zero_trust_access_group/list_data_source_schema.go index c68211d5b0..3eec9b3d10 100644 --- a/internal/services/zero_trust_access_group/list_data_source_schema.go +++ b/internal/services/zero_trust_access_group/list_data_source_schema.go @@ -238,6 +238,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsExcludeIPListDataSourceModel](ctx), @@ -484,6 +494,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsIncludeIPListDataSourceModel](ctx), @@ -730,6 +750,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsIsDefaultLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsIsDefaultIPListDataSourceModel](ctx), @@ -980,6 +1010,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupsRequireIPListDataSourceModel](ctx), diff --git a/internal/services/zero_trust_access_group/model.go b/internal/services/zero_trust_access_group/model.go index 1e6da02fc3..72dc405292 100644 --- a/internal/services/zero_trust_access_group/model.go +++ b/internal/services/zero_trust_access_group/model.go @@ -51,6 +51,7 @@ type ZeroTrustAccessGroupIncludeModel struct { ExternalEvaluation *ZeroTrustAccessGroupIncludeExternalEvaluationModel `tfsdk:"external_evaluation" json:"external_evaluation,optional"` GitHubOrganization *ZeroTrustAccessGroupIncludeGitHubOrganizationModel `tfsdk:"github_organization" json:"github-organization,optional"` GSuite *ZeroTrustAccessGroupIncludeGSuiteModel `tfsdk:"gsuite" json:"gsuite,optional"` + LoginMethod *ZeroTrustAccessGroupIncludeLoginMethodModel `tfsdk:"login_method" json:"login_method,optional"` IPList *ZeroTrustAccessGroupIncludeIPListModel `tfsdk:"ip_list" json:"ip_list,optional"` IP *ZeroTrustAccessGroupIncludeIPModel `tfsdk:"ip" json:"ip,optional"` Okta *ZeroTrustAccessGroupIncludeOktaModel `tfsdk:"okta" json:"okta,optional"` @@ -126,6 +127,10 @@ type ZeroTrustAccessGroupIncludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessGroupIncludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessGroupIncludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -166,6 +171,7 @@ type ZeroTrustAccessGroupExcludeModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupExcludeExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupExcludeGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessGroupExcludeGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupExcludeLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessGroupExcludeIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessGroupExcludeIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessGroupExcludeOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -241,6 +247,10 @@ type ZeroTrustAccessGroupExcludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessGroupExcludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessGroupExcludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -281,6 +291,7 @@ type ZeroTrustAccessGroupRequireModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessGroupRequireExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessGroupRequireGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessGroupRequireGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessGroupRequireLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessGroupRequireIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessGroupRequireIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessGroupRequireOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -356,6 +367,10 @@ type ZeroTrustAccessGroupRequireGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessGroupRequireLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessGroupRequireIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } diff --git a/internal/services/zero_trust_access_group/schema.go b/internal/services/zero_trust_access_group/schema.go index 1bcccbfe52..b4639a5c59 100644 --- a/internal/services/zero_trust_access_group/schema.go +++ b/internal/services/zero_trust_access_group/schema.go @@ -201,6 +201,15 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Optional: true, Attributes: map[string]schema.Attribute{ @@ -457,6 +466,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupExcludeLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, @@ -719,6 +739,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessGroupRequireLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, diff --git a/internal/services/zero_trust_access_identity_provider/data_source.go b/internal/services/zero_trust_access_identity_provider/data_source.go index a447b370cb..3d5d5b0c1a 100644 --- a/internal/services/zero_trust_access_identity_provider/data_source.go +++ b/internal/services/zero_trust_access_identity_provider/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustAccessIdentityProviderDataSource) Read(ctx context.Context, re return } - env := ZeroTrustAccessIdentityProviderResultListDataSourceEnvelope{} + env := ZeroTrustAccessIdentityProvidersResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.IdentityProviders.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustAccessIdentityProviderDataSource) Read(ctx context.Context, re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.IdentityProviderID = ts[0].IdentityProviderID + data.IdentityProviderID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_access_identity_provider/data_source_model.go b/internal/services/zero_trust_access_identity_provider/data_source_model.go index c599bb0f60..c430731ca6 100644 --- a/internal/services/zero_trust_access_identity_provider/data_source_model.go +++ b/internal/services/zero_trust_access_identity_provider/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustAccessIdentityProviderResultDataSourceEnvelope struct { Result ZeroTrustAccessIdentityProviderDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessIdentityProviderResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessIdentityProviderDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessIdentityProviderDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` IdentityProviderID types.String `tfsdk:"identity_provider_id" path:"identity_provider_id,optional"` diff --git a/internal/services/zero_trust_access_infrastructure_target/data_source.go b/internal/services/zero_trust_access_infrastructure_target/data_source.go index 2adbb7ce67..71466b4d17 100644 --- a/internal/services/zero_trust_access_infrastructure_target/data_source.go +++ b/internal/services/zero_trust_access_infrastructure_target/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustAccessInfrastructureTargetDataSource) Read(ctx context.Context return } - env := ZeroTrustAccessInfrastructureTargetResultListDataSourceEnvelope{} + env := ZeroTrustAccessInfrastructureTargetsResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Access.Infrastructure.Targets.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustAccessInfrastructureTargetDataSource) Read(ctx context.Context } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.TargetID = ts[0].TargetID + data.TargetID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_access_infrastructure_target/data_source_model.go b/internal/services/zero_trust_access_infrastructure_target/data_source_model.go index d0c113bdce..f5761438dc 100644 --- a/internal/services/zero_trust_access_infrastructure_target/data_source_model.go +++ b/internal/services/zero_trust_access_infrastructure_target/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustAccessInfrastructureTargetResultDataSourceEnvelope struct { Result ZeroTrustAccessInfrastructureTargetDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessInfrastructureTargetResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessInfrastructureTargetDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessInfrastructureTargetDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TargetID types.String `tfsdk:"target_id" path:"target_id,optional"` @@ -45,6 +41,10 @@ func (m *ZeroTrustAccessInfrastructureTargetDataSourceModel) toListParams(_ cont for _, item := range *m.Filter.IPs { mFilterIPs = append(mFilterIPs, item.ValueString()) } + mFilterTargetIDs := []string{} + for _, item := range *m.Filter.TargetIDs { + mFilterTargetIDs = append(mFilterTargetIDs, item.ValueString()) + } mFilterCreatedAfter, errs := m.Filter.CreatedAfter.ValueRFC3339Time() diags.Append(errs...) mFilterCreatedBefore, errs := m.Filter.CreatedBefore.ValueRFC3339Time() @@ -57,6 +57,7 @@ func (m *ZeroTrustAccessInfrastructureTargetDataSourceModel) toListParams(_ cont params = zero_trust.AccessInfrastructureTargetListParams{ AccountID: cloudflare.F(m.AccountID.ValueString()), IPs: cloudflare.F(mFilterIPs), + TargetIDs: cloudflare.F(mFilterTargetIDs), } if !m.Filter.CreatedAfter.IsNull() { @@ -74,12 +75,27 @@ func (m *ZeroTrustAccessInfrastructureTargetDataSourceModel) toListParams(_ cont if !m.Filter.HostnameContains.IsNull() { params.HostnameContains = cloudflare.F(m.Filter.HostnameContains.ValueString()) } + if !m.Filter.IPLike.IsNull() { + params.IPLike = cloudflare.F(m.Filter.IPLike.ValueString()) + } if !m.Filter.IPV4.IsNull() { params.IPV4 = cloudflare.F(m.Filter.IPV4.ValueString()) } if !m.Filter.IPV6.IsNull() { params.IPV6 = cloudflare.F(m.Filter.IPV6.ValueString()) } + if !m.Filter.IPV4End.IsNull() { + params.IPV4End = cloudflare.F(m.Filter.IPV4End.ValueString()) + } + if !m.Filter.IPV4Start.IsNull() { + params.IPV4Start = cloudflare.F(m.Filter.IPV4Start.ValueString()) + } + if !m.Filter.IPV6End.IsNull() { + params.IPV6End = cloudflare.F(m.Filter.IPV6End.ValueString()) + } + if !m.Filter.IPV6Start.IsNull() { + params.IPV6Start = cloudflare.F(m.Filter.IPV6Start.ValueString()) + } if !m.Filter.ModifiedAfter.IsNull() { params.ModifiedAfter = cloudflare.F(mFilterModifiedAfter) } @@ -117,11 +133,17 @@ type ZeroTrustAccessInfrastructureTargetFindOneByDataSourceModel struct { Direction types.String `tfsdk:"direction" query:"direction,optional"` Hostname types.String `tfsdk:"hostname" query:"hostname,optional"` HostnameContains types.String `tfsdk:"hostname_contains" query:"hostname_contains,optional"` + IPLike types.String `tfsdk:"ip_like" query:"ip_like,optional"` IPV4 types.String `tfsdk:"ip_v4" query:"ip_v4,optional"` IPV6 types.String `tfsdk:"ip_v6" query:"ip_v6,optional"` IPs *[]types.String `tfsdk:"ips" query:"ips,optional"` + IPV4End types.String `tfsdk:"ipv4_end" query:"ipv4_end,optional"` + IPV4Start types.String `tfsdk:"ipv4_start" query:"ipv4_start,optional"` + IPV6End types.String `tfsdk:"ipv6_end" query:"ipv6_end,optional"` + IPV6Start types.String `tfsdk:"ipv6_start" query:"ipv6_start,optional"` ModifiedAfter timetypes.RFC3339 `tfsdk:"modified_after" query:"modified_after,optional" format:"date-time"` ModifiedBefore timetypes.RFC3339 `tfsdk:"modified_before" query:"modified_before,optional" format:"date-time"` Order types.String `tfsdk:"order" query:"order,optional"` + TargetIDs *[]types.String `tfsdk:"target_ids" query:"target_ids,optional"` VirtualNetworkID types.String `tfsdk:"virtual_network_id" query:"virtual_network_id,optional"` } diff --git a/internal/services/zero_trust_access_infrastructure_target/data_source_schema.go b/internal/services/zero_trust_access_infrastructure_target/data_source_schema.go index d19550a69d..728b2532be 100644 --- a/internal/services/zero_trust_access_infrastructure_target/data_source_schema.go +++ b/internal/services/zero_trust_access_infrastructure_target/data_source_schema.go @@ -112,6 +112,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Partial match to the hostname of a target", Optional: true, }, + "ip_like": schema.StringAttribute{ + Description: "Filters for targets whose IP addresses look like the specified string.\nSupports `*` as a wildcard character", + Optional: true, + }, "ip_v4": schema.StringAttribute{ Description: "IPv4 address of the target", Optional: true, @@ -125,6 +129,22 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Optional: true, ElementType: types.StringType, }, + "ipv4_end": schema.StringAttribute{ + Description: "Defines an IPv4 filter range's ending value (inclusive). Requires\n`ipv4_start` to be specified as well.", + Optional: true, + }, + "ipv4_start": schema.StringAttribute{ + Description: "Defines an IPv4 filter range's starting value (inclusive). Requires\n`ipv4_end` to be specified as well.", + Optional: true, + }, + "ipv6_end": schema.StringAttribute{ + Description: "Defines an IPv6 filter range's ending value (inclusive). Requires\n`ipv6_start` to be specified as well.", + Optional: true, + }, + "ipv6_start": schema.StringAttribute{ + Description: "Defines an IPv6 filter range's starting value (inclusive). Requires\n`ipv6_end` to be specified as well.", + Optional: true, + }, "modified_after": schema.StringAttribute{ Description: "Date and time at which the target was modified after (inclusive)", Optional: true, @@ -142,6 +162,11 @@ func DataSourceSchema(ctx context.Context) schema.Schema { stringvalidator.OneOfCaseInsensitive("hostname", "created_at"), }, }, + "target_ids": schema.ListAttribute{ + Description: "Filters for targets that have any of the following UUIDs. Specify\n`target_ids` multiple times in query parameter to build list of\ncandidates.", + Optional: true, + ElementType: types.StringType, + }, "virtual_network_id": schema.StringAttribute{ Description: "Private virtual network identifier of the target", Optional: true, diff --git a/internal/services/zero_trust_access_infrastructure_target/list_data_source_model.go b/internal/services/zero_trust_access_infrastructure_target/list_data_source_model.go index 9ddd520d81..32b193003e 100644 --- a/internal/services/zero_trust_access_infrastructure_target/list_data_source_model.go +++ b/internal/services/zero_trust_access_infrastructure_target/list_data_source_model.go @@ -24,13 +24,19 @@ type ZeroTrustAccessInfrastructureTargetsDataSourceModel struct { Direction types.String `tfsdk:"direction" query:"direction,optional"` Hostname types.String `tfsdk:"hostname" query:"hostname,optional"` HostnameContains types.String `tfsdk:"hostname_contains" query:"hostname_contains,optional"` + IPLike types.String `tfsdk:"ip_like" query:"ip_like,optional"` IPV4 types.String `tfsdk:"ip_v4" query:"ip_v4,optional"` IPV6 types.String `tfsdk:"ip_v6" query:"ip_v6,optional"` + IPV4End types.String `tfsdk:"ipv4_end" query:"ipv4_end,optional"` + IPV4Start types.String `tfsdk:"ipv4_start" query:"ipv4_start,optional"` + IPV6End types.String `tfsdk:"ipv6_end" query:"ipv6_end,optional"` + IPV6Start types.String `tfsdk:"ipv6_start" query:"ipv6_start,optional"` ModifiedAfter timetypes.RFC3339 `tfsdk:"modified_after" query:"modified_after,optional" format:"date-time"` ModifiedBefore timetypes.RFC3339 `tfsdk:"modified_before" query:"modified_before,optional" format:"date-time"` Order types.String `tfsdk:"order" query:"order,optional"` VirtualNetworkID types.String `tfsdk:"virtual_network_id" query:"virtual_network_id,optional"` IPs *[]types.String `tfsdk:"ips" query:"ips,optional"` + TargetIDs *[]types.String `tfsdk:"target_ids" query:"target_ids,optional"` MaxItems types.Int64 `tfsdk:"max_items"` Result customfield.NestedObjectList[ZeroTrustAccessInfrastructureTargetsResultDataSourceModel] `tfsdk:"result"` } @@ -40,6 +46,10 @@ func (m *ZeroTrustAccessInfrastructureTargetsDataSourceModel) toListParams(_ con for _, item := range *m.IPs { mIPs = append(mIPs, item.ValueString()) } + mTargetIDs := []string{} + for _, item := range *m.TargetIDs { + mTargetIDs = append(mTargetIDs, item.ValueString()) + } mCreatedAfter, errs := m.CreatedAfter.ValueRFC3339Time() diags.Append(errs...) mCreatedBefore, errs := m.CreatedBefore.ValueRFC3339Time() @@ -52,6 +62,7 @@ func (m *ZeroTrustAccessInfrastructureTargetsDataSourceModel) toListParams(_ con params = zero_trust.AccessInfrastructureTargetListParams{ AccountID: cloudflare.F(m.AccountID.ValueString()), IPs: cloudflare.F(mIPs), + TargetIDs: cloudflare.F(mTargetIDs), } if !m.CreatedAfter.IsNull() { @@ -69,12 +80,27 @@ func (m *ZeroTrustAccessInfrastructureTargetsDataSourceModel) toListParams(_ con if !m.HostnameContains.IsNull() { params.HostnameContains = cloudflare.F(m.HostnameContains.ValueString()) } + if !m.IPLike.IsNull() { + params.IPLike = cloudflare.F(m.IPLike.ValueString()) + } if !m.IPV4.IsNull() { params.IPV4 = cloudflare.F(m.IPV4.ValueString()) } if !m.IPV6.IsNull() { params.IPV6 = cloudflare.F(m.IPV6.ValueString()) } + if !m.IPV4End.IsNull() { + params.IPV4End = cloudflare.F(m.IPV4End.ValueString()) + } + if !m.IPV4Start.IsNull() { + params.IPV4Start = cloudflare.F(m.IPV4Start.ValueString()) + } + if !m.IPV6End.IsNull() { + params.IPV6End = cloudflare.F(m.IPV6End.ValueString()) + } + if !m.IPV6Start.IsNull() { + params.IPV6Start = cloudflare.F(m.IPV6Start.ValueString()) + } if !m.ModifiedAfter.IsNull() { params.ModifiedAfter = cloudflare.F(mModifiedAfter) } diff --git a/internal/services/zero_trust_access_infrastructure_target/list_data_source_schema.go b/internal/services/zero_trust_access_infrastructure_target/list_data_source_schema.go index 133c46caac..172d2b455a 100644 --- a/internal/services/zero_trust_access_infrastructure_target/list_data_source_schema.go +++ b/internal/services/zero_trust_access_infrastructure_target/list_data_source_schema.go @@ -49,6 +49,10 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "Partial match to the hostname of a target", Optional: true, }, + "ip_like": schema.StringAttribute{ + Description: "Filters for targets whose IP addresses look like the specified string.\nSupports `*` as a wildcard character", + Optional: true, + }, "ip_v4": schema.StringAttribute{ Description: "IPv4 address of the target", Optional: true, @@ -57,6 +61,22 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Description: "IPv6 address of the target", Optional: true, }, + "ipv4_end": schema.StringAttribute{ + Description: "Defines an IPv4 filter range's ending value (inclusive). Requires\n`ipv4_start` to be specified as well.", + Optional: true, + }, + "ipv4_start": schema.StringAttribute{ + Description: "Defines an IPv4 filter range's starting value (inclusive). Requires\n`ipv4_end` to be specified as well.", + Optional: true, + }, + "ipv6_end": schema.StringAttribute{ + Description: "Defines an IPv6 filter range's ending value (inclusive). Requires\n`ipv6_start` to be specified as well.", + Optional: true, + }, + "ipv6_start": schema.StringAttribute{ + Description: "Defines an IPv6 filter range's starting value (inclusive). Requires\n`ipv6_end` to be specified as well.", + Optional: true, + }, "modified_after": schema.StringAttribute{ Description: "Date and time at which the target was modified after (inclusive)", Optional: true, @@ -83,6 +103,11 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Optional: true, ElementType: types.StringType, }, + "target_ids": schema.ListAttribute{ + Description: "Filters for targets that have any of the following UUIDs. Specify\n`target_ids` multiple times in query parameter to build list of\ncandidates.", + Optional: true, + ElementType: types.StringType, + }, "max_items": schema.Int64Attribute{ Description: "Max items to fetch, default: 1000", Optional: true, diff --git a/internal/services/zero_trust_access_mtls_certificate/data_source_model.go b/internal/services/zero_trust_access_mtls_certificate/data_source_model.go index b3f012fd37..7a03b4317b 100644 --- a/internal/services/zero_trust_access_mtls_certificate/data_source_model.go +++ b/internal/services/zero_trust_access_mtls_certificate/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustAccessMTLSCertificateResultDataSourceEnvelope struct { Result ZeroTrustAccessMTLSCertificateDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessMTLSCertificateResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessMTLSCertificateDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessMTLSCertificateDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CertificateID types.String `tfsdk:"certificate_id" path:"certificate_id,optional"` diff --git a/internal/services/zero_trust_access_mtls_hostname_settings/data_source_model.go b/internal/services/zero_trust_access_mtls_hostname_settings/data_source_model.go index e4c1f00f25..a9e01e17dd 100644 --- a/internal/services/zero_trust_access_mtls_hostname_settings/data_source_model.go +++ b/internal/services/zero_trust_access_mtls_hostname_settings/data_source_model.go @@ -16,8 +16,11 @@ type ZeroTrustAccessMTLSHostnameSettingsResultDataSourceEnvelope struct { } type ZeroTrustAccessMTLSHostnameSettingsDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + ChinaNetwork types.Bool `tfsdk:"china_network" json:"china_network,computed"` + ClientCertificateForwarding types.Bool `tfsdk:"client_certificate_forwarding" json:"client_certificate_forwarding,computed"` + Hostname types.String `tfsdk:"hostname" json:"hostname,computed"` } func (m *ZeroTrustAccessMTLSHostnameSettingsDataSourceModel) toReadParams(_ context.Context) (params zero_trust.AccessCertificateSettingGetParams, diags diag.Diagnostics) { diff --git a/internal/services/zero_trust_access_mtls_hostname_settings/data_source_schema.go b/internal/services/zero_trust_access_mtls_hostname_settings/data_source_schema.go index 9471ee443b..de9b5f372a 100644 --- a/internal/services/zero_trust_access_mtls_hostname_settings/data_source_schema.go +++ b/internal/services/zero_trust_access_mtls_hostname_settings/data_source_schema.go @@ -24,6 +24,18 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "The Zone ID to use for this endpoint. Mutually exclusive with the Account ID.", Optional: true, }, + "china_network": schema.BoolAttribute{ + Description: "Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled.", + Computed: true, + }, + "client_certificate_forwarding": schema.BoolAttribute{ + Description: "Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin.", + Computed: true, + }, + "hostname": schema.StringAttribute{ + Description: "The hostname that these settings apply to.", + Computed: true, + }, }, } } diff --git a/internal/services/zero_trust_access_mtls_hostname_settings/model.go b/internal/services/zero_trust_access_mtls_hostname_settings/model.go index 3c7ff21e37..9bfbc2d459 100644 --- a/internal/services/zero_trust_access_mtls_hostname_settings/model.go +++ b/internal/services/zero_trust_access_mtls_hostname_settings/model.go @@ -12,9 +12,12 @@ type ZeroTrustAccessMTLSHostnameSettingsResultEnvelope struct { } type ZeroTrustAccessMTLSHostnameSettingsModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` - Settings *[]*ZeroTrustAccessMTLSHostnameSettingsSettingsModel `tfsdk:"settings" json:"settings,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,optional"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` + Settings *[]*ZeroTrustAccessMTLSHostnameSettingsSettingsModel `tfsdk:"settings" json:"settings,required"` + ChinaNetwork types.Bool `tfsdk:"china_network" json:"china_network,computed"` + ClientCertificateForwarding types.Bool `tfsdk:"client_certificate_forwarding" json:"client_certificate_forwarding,computed"` + Hostname types.String `tfsdk:"hostname" json:"hostname,computed"` } func (m ZeroTrustAccessMTLSHostnameSettingsModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zero_trust_access_mtls_hostname_settings/schema.go b/internal/services/zero_trust_access_mtls_hostname_settings/schema.go index f0138df64c..1a0b91d3ed 100644 --- a/internal/services/zero_trust_access_mtls_hostname_settings/schema.go +++ b/internal/services/zero_trust_access_mtls_hostname_settings/schema.go @@ -47,6 +47,18 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "china_network": schema.BoolAttribute{ + Description: "Request client certificates for this hostname in China. Can only be set to true if this zone is china network enabled.", + Computed: true, + }, + "client_certificate_forwarding": schema.BoolAttribute{ + Description: "Client Certificate Forwarding is a feature that takes the client cert provided by the eyeball to the edge, and forwards it to the origin as a HTTP header to allow logging on the origin.", + Computed: true, + }, + "hostname": schema.StringAttribute{ + Description: "The hostname that these settings apply to.", + Computed: true, + }, }, } } diff --git a/internal/services/zero_trust_access_policy/data_source_model.go b/internal/services/zero_trust_access_policy/data_source_model.go index ae4710395b..f27e21a673 100644 --- a/internal/services/zero_trust_access_policy/data_source_model.go +++ b/internal/services/zero_trust_access_policy/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustAccessPolicyResultDataSourceEnvelope struct { Result ZeroTrustAccessPolicyDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessPolicyResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessPolicyDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessPolicyDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PolicyID types.String `tfsdk:"policy_id" path:"policy_id,optional"` @@ -81,6 +77,7 @@ type ZeroTrustAccessPolicyExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPolicyExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPolicyExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPolicyExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPolicyExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPolicyExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPolicyExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPolicyExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -156,6 +153,10 @@ type ZeroTrustAccessPolicyExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPolicyExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPolicyExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -196,6 +197,7 @@ type ZeroTrustAccessPolicyIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPolicyIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPolicyIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPolicyIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPolicyIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPolicyIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPolicyIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPolicyIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -271,6 +273,10 @@ type ZeroTrustAccessPolicyIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPolicyIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPolicyIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -311,6 +317,7 @@ type ZeroTrustAccessPolicyRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPolicyRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPolicyRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPolicyRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPolicyRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPolicyRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPolicyRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPolicyRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -386,6 +393,10 @@ type ZeroTrustAccessPolicyRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPolicyRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPolicyRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } diff --git a/internal/services/zero_trust_access_policy/data_source_schema.go b/internal/services/zero_trust_access_policy/data_source_schema.go index a09052a6b0..4bc6240f4c 100644 --- a/internal/services/zero_trust_access_policy/data_source_schema.go +++ b/internal/services/zero_trust_access_policy/data_source_schema.go @@ -290,6 +290,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyExcludeIPListDataSourceModel](ctx), @@ -536,6 +546,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyIncludeIPListDataSourceModel](ctx), @@ -782,6 +802,16 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyRequireIPListDataSourceModel](ctx), diff --git a/internal/services/zero_trust_access_policy/list_data_source_model.go b/internal/services/zero_trust_access_policy/list_data_source_model.go index c9ad3c8a15..928c7ceb6a 100644 --- a/internal/services/zero_trust_access_policy/list_data_source_model.go +++ b/internal/services/zero_trust_access_policy/list_data_source_model.go @@ -73,6 +73,7 @@ type ZeroTrustAccessPoliciesExcludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPoliciesExcludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPoliciesExcludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPoliciesExcludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPoliciesExcludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPoliciesExcludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPoliciesExcludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPoliciesExcludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -148,6 +149,10 @@ type ZeroTrustAccessPoliciesExcludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPoliciesExcludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPoliciesExcludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -188,6 +193,7 @@ type ZeroTrustAccessPoliciesIncludeDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPoliciesIncludeExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPoliciesIncludeGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPoliciesIncludeGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPoliciesIncludeLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPoliciesIncludeIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPoliciesIncludeIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPoliciesIncludeOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -263,6 +269,10 @@ type ZeroTrustAccessPoliciesIncludeGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPoliciesIncludeLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPoliciesIncludeIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } @@ -303,6 +313,7 @@ type ZeroTrustAccessPoliciesRequireDataSourceModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPoliciesRequireExternalEvaluationDataSourceModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPoliciesRequireGitHubOrganizationDataSourceModel] `tfsdk:"github_organization" json:"github-organization,computed"` GSuite customfield.NestedObject[ZeroTrustAccessPoliciesRequireGSuiteDataSourceModel] `tfsdk:"gsuite" json:"gsuite,computed"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPoliciesRequireLoginMethodDataSourceModel] `tfsdk:"login_method" json:"login_method,computed"` IPList customfield.NestedObject[ZeroTrustAccessPoliciesRequireIPListDataSourceModel] `tfsdk:"ip_list" json:"ip_list,computed"` IP customfield.NestedObject[ZeroTrustAccessPoliciesRequireIPDataSourceModel] `tfsdk:"ip" json:"ip,computed"` Okta customfield.NestedObject[ZeroTrustAccessPoliciesRequireOktaDataSourceModel] `tfsdk:"okta" json:"okta,computed"` @@ -378,6 +389,10 @@ type ZeroTrustAccessPoliciesRequireGSuiteDataSourceModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,computed"` } +type ZeroTrustAccessPoliciesRequireLoginMethodDataSourceModel struct { + ID types.String `tfsdk:"id" json:"id,computed"` +} + type ZeroTrustAccessPoliciesRequireIPListDataSourceModel struct { ID types.String `tfsdk:"id" json:"id,computed"` } diff --git a/internal/services/zero_trust_access_policy/list_data_source_schema.go b/internal/services/zero_trust_access_policy/list_data_source_schema.go index 593a842a4f..56b2255b86 100644 --- a/internal/services/zero_trust_access_policy/list_data_source_schema.go +++ b/internal/services/zero_trust_access_policy/list_data_source_schema.go @@ -273,6 +273,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesExcludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesExcludeIPListDataSourceModel](ctx), @@ -519,6 +529,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesIncludeLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesIncludeIPListDataSourceModel](ctx), @@ -781,6 +801,16 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesRequireLoginMethodDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Computed: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPoliciesRequireIPListDataSourceModel](ctx), diff --git a/internal/services/zero_trust_access_policy/model.go b/internal/services/zero_trust_access_policy/model.go index 47a664b8f0..6626db0283 100644 --- a/internal/services/zero_trust_access_policy/model.go +++ b/internal/services/zero_trust_access_policy/model.go @@ -58,6 +58,7 @@ type ZeroTrustAccessPolicyIncludeModel struct { ExternalEvaluation *ZeroTrustAccessPolicyIncludeExternalEvaluationModel `tfsdk:"external_evaluation" json:"external_evaluation,optional"` GitHubOrganization *ZeroTrustAccessPolicyIncludeGitHubOrganizationModel `tfsdk:"github_organization" json:"github-organization,optional"` GSuite *ZeroTrustAccessPolicyIncludeGSuiteModel `tfsdk:"gsuite" json:"gsuite,optional"` + LoginMethod *ZeroTrustAccessPolicyIncludeLoginMethodModel `tfsdk:"login_method" json:"login_method,optional"` IPList *ZeroTrustAccessPolicyIncludeIPListModel `tfsdk:"ip_list" json:"ip_list,optional"` IP *ZeroTrustAccessPolicyIncludeIPModel `tfsdk:"ip" json:"ip,optional"` Okta *ZeroTrustAccessPolicyIncludeOktaModel `tfsdk:"okta" json:"okta,optional"` @@ -133,6 +134,10 @@ type ZeroTrustAccessPolicyIncludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessPolicyIncludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessPolicyIncludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -179,6 +184,7 @@ type ZeroTrustAccessPolicyExcludeModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPolicyExcludeExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPolicyExcludeGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessPolicyExcludeGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPolicyExcludeLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessPolicyExcludeIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessPolicyExcludeIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessPolicyExcludeOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -254,6 +260,10 @@ type ZeroTrustAccessPolicyExcludeGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessPolicyExcludeLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessPolicyExcludeIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } @@ -294,6 +304,7 @@ type ZeroTrustAccessPolicyRequireModel struct { ExternalEvaluation customfield.NestedObject[ZeroTrustAccessPolicyRequireExternalEvaluationModel] `tfsdk:"external_evaluation" json:"external_evaluation,computed_optional"` GitHubOrganization customfield.NestedObject[ZeroTrustAccessPolicyRequireGitHubOrganizationModel] `tfsdk:"github_organization" json:"github-organization,computed_optional"` GSuite customfield.NestedObject[ZeroTrustAccessPolicyRequireGSuiteModel] `tfsdk:"gsuite" json:"gsuite,computed_optional"` + LoginMethod customfield.NestedObject[ZeroTrustAccessPolicyRequireLoginMethodModel] `tfsdk:"login_method" json:"login_method,computed_optional"` IPList customfield.NestedObject[ZeroTrustAccessPolicyRequireIPListModel] `tfsdk:"ip_list" json:"ip_list,computed_optional"` IP customfield.NestedObject[ZeroTrustAccessPolicyRequireIPModel] `tfsdk:"ip" json:"ip,computed_optional"` Okta customfield.NestedObject[ZeroTrustAccessPolicyRequireOktaModel] `tfsdk:"okta" json:"okta,computed_optional"` @@ -369,6 +380,10 @@ type ZeroTrustAccessPolicyRequireGSuiteModel struct { IdentityProviderID types.String `tfsdk:"identity_provider_id" json:"identity_provider_id,required"` } +type ZeroTrustAccessPolicyRequireLoginMethodModel struct { + ID types.String `tfsdk:"id" json:"id,required"` +} + type ZeroTrustAccessPolicyRequireIPListModel struct { ID types.String `tfsdk:"id" json:"id,required"` } diff --git a/internal/services/zero_trust_access_policy/schema.go b/internal/services/zero_trust_access_policy/schema.go index 55b7648c50..6c5b747157 100644 --- a/internal/services/zero_trust_access_policy/schema.go +++ b/internal/services/zero_trust_access_policy/schema.go @@ -214,6 +214,15 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Optional: true, Attributes: map[string]schema.Attribute{ @@ -520,6 +529,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyExcludeLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, @@ -782,6 +802,17 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "login_method": schema.SingleNestedAttribute{ + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustAccessPolicyRequireLoginMethodModel](ctx), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of an identity provider.", + Required: true, + }, + }, + }, "ip_list": schema.SingleNestedAttribute{ Computed: true, Optional: true, diff --git a/internal/services/zero_trust_access_service_token/data_source.go b/internal/services/zero_trust_access_service_token/data_source.go index 465557dc13..34e729dd48 100644 --- a/internal/services/zero_trust_access_service_token/data_source.go +++ b/internal/services/zero_trust_access_service_token/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustAccessServiceTokenDataSource) Read(ctx context.Context, req da return } - env := ZeroTrustAccessServiceTokenResultListDataSourceEnvelope{} + env := ZeroTrustAccessServiceTokensResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Access.ServiceTokens.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustAccessServiceTokenDataSource) Read(ctx context.Context, req da } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.ServiceTokenID = ts[0].ServiceTokenID + data.ServiceTokenID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_access_service_token/data_source_model.go b/internal/services/zero_trust_access_service_token/data_source_model.go index 93a8a692fc..027e51abc5 100644 --- a/internal/services/zero_trust_access_service_token/data_source_model.go +++ b/internal/services/zero_trust_access_service_token/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustAccessServiceTokenResultDataSourceEnvelope struct { Result ZeroTrustAccessServiceTokenDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessServiceTokenResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessServiceTokenDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessServiceTokenDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ServiceTokenID types.String `tfsdk:"service_token_id" path:"service_token_id,optional"` diff --git a/internal/services/zero_trust_access_tag/data_source_model.go b/internal/services/zero_trust_access_tag/data_source_model.go index 189b9243d1..e5ac95f5b6 100644 --- a/internal/services/zero_trust_access_tag/data_source_model.go +++ b/internal/services/zero_trust_access_tag/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustAccessTagResultDataSourceEnvelope struct { Result ZeroTrustAccessTagDataSourceModel `json:"result,computed"` } -type ZeroTrustAccessTagResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustAccessTagDataSourceModel] `json:"result,computed"` -} - type ZeroTrustAccessTagDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TagName types.String `tfsdk:"tag_name" path:"tag_name,optional"` diff --git a/internal/services/zero_trust_device_custom_profile/data_source_model.go b/internal/services/zero_trust_device_custom_profile/data_source_model.go index 81458e3bb8..ddb7097214 100644 --- a/internal/services/zero_trust_device_custom_profile/data_source_model.go +++ b/internal/services/zero_trust_device_custom_profile/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustDeviceCustomProfileResultDataSourceEnvelope struct { Result ZeroTrustDeviceCustomProfileDataSourceModel `json:"result,computed"` } -type ZeroTrustDeviceCustomProfileResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDeviceCustomProfileDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDeviceCustomProfileDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` PolicyID types.String `tfsdk:"policy_id" path:"policy_id,computed_optional"` diff --git a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_model.go b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_model.go index 2ae7d155c1..bd52c75830 100644 --- a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_model.go +++ b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +17,11 @@ type ZeroTrustDeviceCustomProfileLocalDomainFallbackResultDataSourceEnvelope str } type ZeroTrustDeviceCustomProfileLocalDomainFallbackDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - PolicyID types.String `tfsdk:"policy_id" path:"policy_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + PolicyID types.String `tfsdk:"policy_id" path:"policy_id,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` + DNSServer customfield.List[types.String] `tfsdk:"dns_server" json:"dns_server,computed"` } func (m *ZeroTrustDeviceCustomProfileLocalDomainFallbackDataSourceModel) toReadParams(_ context.Context) (params zero_trust.DevicePolicyCustomFallbackDomainGetParams, diags diag.Diagnostics) { diff --git a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_schema.go b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_schema.go index a9ac122cef..d895393bde 100644 --- a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_schema.go +++ b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/data_source_schema.go @@ -5,8 +5,10 @@ package zero_trust_device_custom_profile_local_domain_fallback import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustDeviceCustomProfileLocalDomainFallbackDataSource)(nil) @@ -21,6 +23,20 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Device ID.", Required: true, }, + "description": schema.StringAttribute{ + Description: "A description of the fallback domain, displayed in the client UI.", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "The domain suffix to match when resolving locally.", + Computed: true, + }, + "dns_server": schema.ListAttribute{ + Description: "A list of IP addresses to handle domain resolution.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, }, } } diff --git a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/model.go b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/model.go index 5415e30117..b251731fc1 100644 --- a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/model.go +++ b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/model.go @@ -4,6 +4,7 @@ package zero_trust_device_custom_profile_local_domain_fallback import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -12,10 +13,13 @@ type ZeroTrustDeviceCustomProfileLocalDomainFallbackResultEnvelope struct { } type ZeroTrustDeviceCustomProfileLocalDomainFallbackModel struct { - ID types.String `tfsdk:"id" json:"-,computed"` - PolicyID types.String `tfsdk:"policy_id" path:"policy_id,required"` - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - Domains *[]*ZeroTrustDeviceCustomProfileLocalDomainFallbackDomainsModel `tfsdk:"domains" json:"domains,required"` + ID types.String `tfsdk:"id" json:"-,computed"` + PolicyID types.String `tfsdk:"policy_id" path:"policy_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Domains *[]*ZeroTrustDeviceCustomProfileLocalDomainFallbackDomainsModel `tfsdk:"domains" json:"domains,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` + DNSServer customfield.List[types.String] `tfsdk:"dns_server" json:"dns_server,computed"` } func (m ZeroTrustDeviceCustomProfileLocalDomainFallbackModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/schema.go b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/schema.go index 37326ba4a9..dbf46dc1ef 100644 --- a/internal/services/zero_trust_device_custom_profile_local_domain_fallback/schema.go +++ b/internal/services/zero_trust_device_custom_profile_local_domain_fallback/schema.go @@ -5,6 +5,7 @@ package zero_trust_device_custom_profile_local_domain_fallback import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -51,6 +52,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "description": schema.StringAttribute{ + Description: "A description of the fallback domain, displayed in the client UI.", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "The domain suffix to match when resolving locally.", + Computed: true, + }, + "dns_server": schema.ListAttribute{ + Description: "A list of IP addresses to handle domain resolution.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, }, } } diff --git a/internal/services/zero_trust_device_default_profile/model.go b/internal/services/zero_trust_device_default_profile/model.go index 936c4d4930..4b06d7ec66 100644 --- a/internal/services/zero_trust_device_default_profile/model.go +++ b/internal/services/zero_trust_device_default_profile/model.go @@ -13,6 +13,7 @@ type ZeroTrustDeviceDefaultProfileResultEnvelope struct { } type ZeroTrustDeviceDefaultProfileModel struct { + ID types.String `tfsdk:"id" json:"-,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` AllowModeSwitch types.Bool `tfsdk:"allow_mode_switch" json:"allow_mode_switch,optional"` AllowUpdates types.Bool `tfsdk:"allow_updates" json:"allow_updates,optional"` diff --git a/internal/services/zero_trust_device_default_profile/resource.go b/internal/services/zero_trust_device_default_profile/resource.go index 431c84b4bd..58d6af841c 100644 --- a/internal/services/zero_trust_device_default_profile/resource.go +++ b/internal/services/zero_trust_device_default_profile/resource.go @@ -12,13 +12,16 @@ import ( "github.com/cloudflare/cloudflare-go/v4/option" "github.com/cloudflare/cloudflare-go/v4/zero_trust" "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/importpath" "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" ) // Ensure provider defined types fully satisfy framework interfaces. var _ resource.ResourceWithConfigure = (*ZeroTrustDeviceDefaultProfileResource)(nil) var _ resource.ResourceWithModifyPlan = (*ZeroTrustDeviceDefaultProfileResource)(nil) +var _ resource.ResourceWithImportState = (*ZeroTrustDeviceDefaultProfileResource)(nil) func NewResource() resource.Resource { return &ZeroTrustDeviceDefaultProfileResource{} @@ -88,6 +91,7 @@ func (r *ZeroTrustDeviceDefaultProfileResource) Create(ctx context.Context, req return } data = &env.Result + data.ID = data.AccountID resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -136,6 +140,7 @@ func (r *ZeroTrustDeviceDefaultProfileResource) Update(ctx context.Context, req return } data = &env.Result + data.ID = data.AccountID resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -175,6 +180,7 @@ func (r *ZeroTrustDeviceDefaultProfileResource) Read(ctx context.Context, req re return } data = &env.Result + data.ID = data.AccountID resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -183,6 +189,48 @@ func (r *ZeroTrustDeviceDefaultProfileResource) Delete(ctx context.Context, req } +func (r *ZeroTrustDeviceDefaultProfileResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + var data *ZeroTrustDeviceDefaultProfileModel = new(ZeroTrustDeviceDefaultProfileModel) + + path := "" + diags := importpath.ParseImportID( + req.ID, + "", + &path, + ) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.AccountID = types.StringValue(path) + + res := new(http.Response) + env := ZeroTrustDeviceDefaultProfileResultEnvelope{*data} + _, err := r.client.ZeroTrust.Devices.Policies.Default.Get( + ctx, + zero_trust.DevicePolicyDefaultGetParams{ + AccountID: cloudflare.F(path), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.Unmarshal(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + data.ID = data.AccountID + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + func (r *ZeroTrustDeviceDefaultProfileResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { if req.State.Raw.IsNull() { resp.Diagnostics.AddWarning( diff --git a/internal/services/zero_trust_device_default_profile/schema.go b/internal/services/zero_trust_device_default_profile/schema.go index 10f8cd3058..e36e45cfb5 100644 --- a/internal/services/zero_trust_device_default_profile/schema.go +++ b/internal/services/zero_trust_device_default_profile/schema.go @@ -8,9 +8,6 @@ import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/float64planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" @@ -21,59 +18,53 @@ var _ resource.ResourceWithConfigValidators = (*ZeroTrustDeviceDefaultProfileRes func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, "account_id": schema.StringAttribute{ Required: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown(), stringplanmodifier.RequiresReplace()}, }, "allow_mode_switch": schema.BoolAttribute{ - Description: "Whether to allow the user to switch WARP between modes.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "Whether to allow the user to switch WARP between modes.", + Optional: true, }, "allow_updates": schema.BoolAttribute{ - Description: "Whether to receive update notifications when a new version of the client is available.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "Whether to receive update notifications when a new version of the client is available.", + Optional: true, }, "allowed_to_leave": schema.BoolAttribute{ - Description: "Whether to allow devices to leave the organization.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "Whether to allow devices to leave the organization.", + Optional: true, }, "auto_connect": schema.Float64Attribute{ - Description: "The amount of time in seconds to reconnect after having been disabled.", - Optional: true, - PlanModifiers: []planmodifier.Float64{float64planmodifier.RequiresReplace()}, + Description: "The amount of time in seconds to reconnect after having been disabled.", + Optional: true, }, "captive_portal": schema.Float64Attribute{ - Description: "Turn on the captive portal after the specified amount of time.", - Optional: true, - PlanModifiers: []planmodifier.Float64{float64planmodifier.RequiresReplace()}, + Description: "Turn on the captive portal after the specified amount of time.", + Optional: true, }, "disable_auto_fallback": schema.BoolAttribute{ - Description: "If the `dns_server` field of a fallback domain is not present, the client will fall back to a best guess of the default/system DNS resolvers unless this policy option is set to `true`.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "If the `dns_server` field of a fallback domain is not present, the client will fall back to a best guess of the default/system DNS resolvers unless this policy option is set to `true`.", + Optional: true, }, "exclude_office_ips": schema.BoolAttribute{ - Description: "Whether to add Microsoft IPs to Split Tunnel exclusions.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "Whether to add Microsoft IPs to Split Tunnel exclusions.", + Optional: true, }, "support_url": schema.StringAttribute{ - Description: "The URL to launch when the Send Feedback button is clicked.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + Description: "The URL to launch when the Send Feedback button is clicked.", + Optional: true, }, "switch_locked": schema.BoolAttribute{ - Description: "Whether to allow the user to turn off the WARP switch and disconnect the client.", - Optional: true, - PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + Description: "Whether to allow the user to turn off the WARP switch and disconnect the client.", + Optional: true, }, "tunnel_protocol": schema.StringAttribute{ - Description: "Determines which tunnel protocol to use.", - Optional: true, - PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + Description: "Determines which tunnel protocol to use.", + Optional: true, }, "service_mode_v2": schema.SingleNestedAttribute{ Computed: true, @@ -89,7 +80,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Optional: true, }, }, - PlanModifiers: []planmodifier.Object{objectplanmodifier.RequiresReplace()}, }, "default": schema.BoolAttribute{ Description: "Whether the policy will be applied to matching devices.", diff --git a/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_model.go b/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_model.go index d513d877dc..90bac533f2 100644 --- a/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_model.go +++ b/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_model.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,7 +17,10 @@ type ZeroTrustDeviceDefaultProfileLocalDomainFallbackResultDataSourceEnvelope st } type ZeroTrustDeviceDefaultProfileLocalDomainFallbackDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` + DNSServer customfield.List[types.String] `tfsdk:"dns_server" json:"dns_server,computed"` } func (m *ZeroTrustDeviceDefaultProfileLocalDomainFallbackDataSourceModel) toReadParams(_ context.Context) (params zero_trust.DevicePolicyDefaultFallbackDomainGetParams, diags diag.Diagnostics) { diff --git a/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_schema.go b/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_schema.go index c856f31f74..0544c19ad8 100644 --- a/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_schema.go +++ b/internal/services/zero_trust_device_default_profile_local_domain_fallback/data_source_schema.go @@ -5,8 +5,10 @@ package zero_trust_device_default_profile_local_domain_fallback import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustDeviceDefaultProfileLocalDomainFallbackDataSource)(nil) @@ -17,6 +19,20 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "account_id": schema.StringAttribute{ Required: true, }, + "description": schema.StringAttribute{ + Description: "A description of the fallback domain, displayed in the client UI.", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "The domain suffix to match when resolving locally.", + Computed: true, + }, + "dns_server": schema.ListAttribute{ + Description: "A list of IP addresses to handle domain resolution.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, }, } } diff --git a/internal/services/zero_trust_device_default_profile_local_domain_fallback/model.go b/internal/services/zero_trust_device_default_profile_local_domain_fallback/model.go index dfe63ba439..8c211d6c65 100644 --- a/internal/services/zero_trust_device_default_profile_local_domain_fallback/model.go +++ b/internal/services/zero_trust_device_default_profile_local_domain_fallback/model.go @@ -4,6 +4,7 @@ package zero_trust_device_default_profile_local_domain_fallback import ( "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -12,8 +13,11 @@ type ZeroTrustDeviceDefaultProfileLocalDomainFallbackResultEnvelope struct { } type ZeroTrustDeviceDefaultProfileLocalDomainFallbackModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - Domains *[]*ZeroTrustDeviceDefaultProfileLocalDomainFallbackDomainsModel `tfsdk:"domains" json:"domains,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + Domains *[]*ZeroTrustDeviceDefaultProfileLocalDomainFallbackDomainsModel `tfsdk:"domains" json:"domains,required"` + Description types.String `tfsdk:"description" json:"description,computed"` + Suffix types.String `tfsdk:"suffix" json:"suffix,computed"` + DNSServer customfield.List[types.String] `tfsdk:"dns_server" json:"dns_server,computed"` } func (m ZeroTrustDeviceDefaultProfileLocalDomainFallbackModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zero_trust_device_default_profile_local_domain_fallback/schema.go b/internal/services/zero_trust_device_default_profile_local_domain_fallback/schema.go index e28e0457d4..b7c0414d7d 100644 --- a/internal/services/zero_trust_device_default_profile_local_domain_fallback/schema.go +++ b/internal/services/zero_trust_device_default_profile_local_domain_fallback/schema.go @@ -5,6 +5,7 @@ package zero_trust_device_default_profile_local_domain_fallback import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" @@ -43,6 +44,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "description": schema.StringAttribute{ + Description: "A description of the fallback domain, displayed in the client UI.", + Computed: true, + }, + "suffix": schema.StringAttribute{ + Description: "The domain suffix to match when resolving locally.", + Computed: true, + }, + "dns_server": schema.ListAttribute{ + Description: "A list of IP addresses to handle domain resolution.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, }, } } diff --git a/internal/services/zero_trust_device_managed_networks/data_source_model.go b/internal/services/zero_trust_device_managed_networks/data_source_model.go index 4341f27024..ec784155a5 100644 --- a/internal/services/zero_trust_device_managed_networks/data_source_model.go +++ b/internal/services/zero_trust_device_managed_networks/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustDeviceManagedNetworksResultDataSourceEnvelope struct { Result ZeroTrustDeviceManagedNetworksDataSourceModel `json:"result,computed"` } -type ZeroTrustDeviceManagedNetworksResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDeviceManagedNetworksDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDeviceManagedNetworksDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` NetworkID types.String `tfsdk:"network_id" path:"network_id,computed_optional"` diff --git a/internal/services/zero_trust_device_managed_networks/schema.go b/internal/services/zero_trust_device_managed_networks/schema.go index 985afd78d3..0438ac0c8f 100644 --- a/internal/services/zero_trust_device_managed_networks/schema.go +++ b/internal/services/zero_trust_device_managed_networks/schema.go @@ -43,7 +43,8 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, "config": schema.SingleNestedAttribute{ - Required: true, + Description: "The configuration object containing information for the WARP client to detect the managed network.", + Required: true, Attributes: map[string]schema.Attribute{ "tls_sockaddr": schema.StringAttribute{ Description: "A network address of the form \"host:port\" that the WARP client will use to detect the presence of a TLS host.", diff --git a/internal/services/zero_trust_device_posture_integration/data_source_model.go b/internal/services/zero_trust_device_posture_integration/data_source_model.go index f86b51dfff..0dc47b3e97 100644 --- a/internal/services/zero_trust_device_posture_integration/data_source_model.go +++ b/internal/services/zero_trust_device_posture_integration/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustDevicePostureIntegrationResultDataSourceEnvelope struct { Result ZeroTrustDevicePostureIntegrationDataSourceModel `json:"result,computed"` } -type ZeroTrustDevicePostureIntegrationResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDevicePostureIntegrationDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDevicePostureIntegrationDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` IntegrationID types.String `tfsdk:"integration_id" path:"integration_id,optional"` diff --git a/internal/services/zero_trust_device_posture_integration/data_source_schema.go b/internal/services/zero_trust_device_posture_integration/data_source_schema.go index 9bb338b811..2395a7eb49 100644 --- a/internal/services/zero_trust_device_posture_integration/data_source_schema.go +++ b/internal/services/zero_trust_device_posture_integration/data_source_schema.go @@ -53,7 +53,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { }, }, "config": schema.SingleNestedAttribute{ - Description: "The Workspace One Config Response.", + Description: "The configuration object containing third-party integration information.", Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDevicePostureIntegrationConfigDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ diff --git a/internal/services/zero_trust_device_posture_integration/list_data_source_schema.go b/internal/services/zero_trust_device_posture_integration/list_data_source_schema.go index 0976b5a1b2..d315ce0b20 100644 --- a/internal/services/zero_trust_device_posture_integration/list_data_source_schema.go +++ b/internal/services/zero_trust_device_posture_integration/list_data_source_schema.go @@ -39,7 +39,7 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, }, "config": schema.SingleNestedAttribute{ - Description: "The Workspace One Config Response.", + Description: "The configuration object containing third-party integration information.", Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDevicePostureIntegrationsConfigDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ diff --git a/internal/services/zero_trust_device_posture_rule/data_source_model.go b/internal/services/zero_trust_device_posture_rule/data_source_model.go index ba0a90b3a7..2ca6882579 100644 --- a/internal/services/zero_trust_device_posture_rule/data_source_model.go +++ b/internal/services/zero_trust_device_posture_rule/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustDevicePostureRuleResultDataSourceEnvelope struct { Result ZeroTrustDevicePostureRuleDataSourceModel `json:"result,computed"` } -type ZeroTrustDevicePostureRuleResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDevicePostureRuleDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDevicePostureRuleDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` diff --git a/internal/services/zero_trust_dex_test/data_source_model.go b/internal/services/zero_trust_dex_test/data_source_model.go index a5adb9eb3e..2f7c83a706 100644 --- a/internal/services/zero_trust_dex_test/data_source_model.go +++ b/internal/services/zero_trust_dex_test/data_source_model.go @@ -16,10 +16,6 @@ type ZeroTrustDEXTestResultDataSourceEnvelope struct { Result ZeroTrustDEXTestDataSourceModel `json:"result,computed"` } -type ZeroTrustDEXTestResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDEXTestDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDEXTestDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` DEXTestID types.String `tfsdk:"dex_test_id" path:"dex_test_id,optional"` diff --git a/internal/services/zero_trust_dlp_custom_profile/data_source_model.go b/internal/services/zero_trust_dlp_custom_profile/data_source_model.go index 19d5ddb5c2..a51fd91cba 100644 --- a/internal/services/zero_trust_dlp_custom_profile/data_source_model.go +++ b/internal/services/zero_trust_dlp_custom_profile/data_source_model.go @@ -21,6 +21,7 @@ type ZeroTrustDLPCustomProfileResultDataSourceEnvelope struct { type ZeroTrustDLPCustomProfileDataSourceModel struct { AccountID types.String `tfsdk:"account_id" path:"account_id,required"` ProfileID types.String `tfsdk:"profile_id" path:"profile_id,required"` + AIContextEnabled types.Bool `tfsdk:"ai_context_enabled" json:"ai_context_enabled,computed"` AllowedMatchCount types.Int64 `tfsdk:"allowed_match_count" json:"allowed_match_count,computed"` ConfidenceThreshold types.String `tfsdk:"confidence_threshold" json:"confidence_threshold,computed"` CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` @@ -72,5 +73,6 @@ type ZeroTrustDLPCustomProfileEntriesPatternDataSourceModel struct { } type ZeroTrustDLPCustomProfileEntriesConfidenceDataSourceModel struct { - Available types.Bool `tfsdk:"available" json:"available,computed"` + AIContextAvailable types.Bool `tfsdk:"ai_context_available" json:"ai_context_available,computed"` + Available types.Bool `tfsdk:"available" json:"available,computed"` } diff --git a/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go b/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go index 831c2e17ac..3081d9d218 100644 --- a/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go +++ b/internal/services/zero_trust_dlp_custom_profile/data_source_schema.go @@ -26,6 +26,9 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "profile_id": schema.StringAttribute{ Required: true, }, + "ai_context_enabled": schema.BoolAttribute{ + Computed: true, + }, "allowed_match_count": schema.Int64Attribute{ Description: "Related DLP policies will trigger when the match count exceeds the number set.", Computed: true, @@ -161,6 +164,9 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDLPCustomProfileEntriesConfidenceDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ + "ai_context_available": schema.BoolAttribute{ + Computed: true, + }, "available": schema.BoolAttribute{ Description: "Indicates whether this entry can be made more or less sensitive by setting a confidence threshold.\nProfiles that use an entry with `available` set to true can use confidence thresholds", Computed: true, diff --git a/internal/services/zero_trust_dlp_custom_profile/model.go b/internal/services/zero_trust_dlp_custom_profile/model.go index 309440473f..34af296226 100644 --- a/internal/services/zero_trust_dlp_custom_profile/model.go +++ b/internal/services/zero_trust_dlp_custom_profile/model.go @@ -17,6 +17,7 @@ type ZeroTrustDLPCustomProfileModel struct { ID types.String `tfsdk:"id" json:"id,computed"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` Profiles customfield.NestedObjectList[ZeroTrustDLPCustomProfileProfilesModel] `tfsdk:"profiles" json:"profiles,computed_optional"` + AIContextEnabled types.Bool `tfsdk:"ai_context_enabled" json:"ai_context_enabled,optional"` ConfidenceThreshold types.String `tfsdk:"confidence_threshold" json:"confidence_threshold,optional"` Description types.String `tfsdk:"description" json:"description,optional"` Name types.String `tfsdk:"name" json:"name,optional"` @@ -42,6 +43,7 @@ func (m ZeroTrustDLPCustomProfileModel) MarshalJSONForUpdate(state ZeroTrustDLPC type ZeroTrustDLPCustomProfileProfilesModel struct { Entries *[]*ZeroTrustDLPCustomProfileProfilesEntriesModel `tfsdk:"entries" json:"entries,required"` Name types.String `tfsdk:"name" json:"name,required"` + AIContextEnabled types.Bool `tfsdk:"ai_context_enabled" json:"ai_context_enabled,optional"` AllowedMatchCount types.Int64 `tfsdk:"allowed_match_count" json:"allowed_match_count,computed_optional"` ConfidenceThreshold types.String `tfsdk:"confidence_threshold" json:"confidence_threshold,optional"` ContextAwareness customfield.NestedObject[ZeroTrustDLPCustomProfileProfilesContextAwarenessModel] `tfsdk:"context_awareness" json:"context_awareness,computed_optional"` diff --git a/internal/services/zero_trust_dlp_custom_profile/schema.go b/internal/services/zero_trust_dlp_custom_profile/schema.go index b04c8f8fcb..87291e19ba 100644 --- a/internal/services/zero_trust_dlp_custom_profile/schema.go +++ b/internal/services/zero_trust_dlp_custom_profile/schema.go @@ -73,6 +73,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { "name": schema.StringAttribute{ Required: true, }, + "ai_context_enabled": schema.BoolAttribute{ + Optional: true, + }, "allowed_match_count": schema.Int64Attribute{ Description: "Related DLP policies will trigger when the match count exceeds the number set.", Computed: true, @@ -145,6 +148,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, PlanModifiers: []planmodifier.List{listplanmodifier.RequiresReplace()}, }, + "ai_context_enabled": schema.BoolAttribute{ + Optional: true, + }, "confidence_threshold": schema.StringAttribute{ Optional: true, }, diff --git a/internal/services/zero_trust_dlp_entry/data_source_model.go b/internal/services/zero_trust_dlp_entry/data_source_model.go index 9035773581..c0cd518964 100644 --- a/internal/services/zero_trust_dlp_entry/data_source_model.go +++ b/internal/services/zero_trust_dlp_entry/data_source_model.go @@ -18,10 +18,6 @@ type ZeroTrustDLPEntryResultDataSourceEnvelope struct { Result ZeroTrustDLPEntryDataSourceModel `json:"result,computed"` } -type ZeroTrustDLPEntryResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDLPEntryDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDLPEntryDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` EntryID types.String `tfsdk:"entry_id" path:"entry_id,optional"` @@ -55,7 +51,8 @@ func (m *ZeroTrustDLPEntryDataSourceModel) toListParams(_ context.Context) (para } type ZeroTrustDLPEntryConfidenceDataSourceModel struct { - Available types.Bool `tfsdk:"available" json:"available,computed"` + AIContextAvailable types.Bool `tfsdk:"ai_context_available" json:"ai_context_available,computed"` + Available types.Bool `tfsdk:"available" json:"available,computed"` } type ZeroTrustDLPEntryPatternDataSourceModel struct { diff --git a/internal/services/zero_trust_dlp_entry/data_source_schema.go b/internal/services/zero_trust_dlp_entry/data_source_schema.go index ac774ee82a..706d3bbb2b 100644 --- a/internal/services/zero_trust_dlp_entry/data_source_schema.go +++ b/internal/services/zero_trust_dlp_entry/data_source_schema.go @@ -64,6 +64,9 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDLPEntryConfidenceDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ + "ai_context_available": schema.BoolAttribute{ + Computed: true, + }, "available": schema.BoolAttribute{ Description: "Indicates whether this entry can be made more or less sensitive by setting a confidence threshold.\nProfiles that use an entry with `available` set to true can use confidence thresholds", Computed: true, diff --git a/internal/services/zero_trust_dlp_entry/list_data_source_model.go b/internal/services/zero_trust_dlp_entry/list_data_source_model.go index a8ee9fbd52..0617481ad4 100644 --- a/internal/services/zero_trust_dlp_entry/list_data_source_model.go +++ b/internal/services/zero_trust_dlp_entry/list_data_source_model.go @@ -52,5 +52,6 @@ type ZeroTrustDLPEntriesPatternDataSourceModel struct { } type ZeroTrustDLPEntriesConfidenceDataSourceModel struct { - Available types.Bool `tfsdk:"available" json:"available,computed"` + AIContextAvailable types.Bool `tfsdk:"ai_context_available" json:"ai_context_available,computed"` + Available types.Bool `tfsdk:"available" json:"available,computed"` } diff --git a/internal/services/zero_trust_dlp_entry/list_data_source_schema.go b/internal/services/zero_trust_dlp_entry/list_data_source_schema.go index 0d6fcd585b..2993590218 100644 --- a/internal/services/zero_trust_dlp_entry/list_data_source_schema.go +++ b/internal/services/zero_trust_dlp_entry/list_data_source_schema.go @@ -87,6 +87,9 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDLPEntriesConfidenceDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ + "ai_context_available": schema.BoolAttribute{ + Computed: true, + }, "available": schema.BoolAttribute{ Description: "Indicates whether this entry can be made more or less sensitive by setting a confidence threshold.\nProfiles that use an entry with `available` set to true can use confidence thresholds", Computed: true, diff --git a/internal/services/zero_trust_dlp_entry/model.go b/internal/services/zero_trust_dlp_entry/model.go index a3332dd8ff..c79a54ae04 100644 --- a/internal/services/zero_trust_dlp_entry/model.go +++ b/internal/services/zero_trust_dlp_entry/model.go @@ -43,5 +43,6 @@ type ZeroTrustDLPEntryPatternModel struct { } type ZeroTrustDLPEntryConfidenceModel struct { - Available types.Bool `tfsdk:"available" json:"available,computed"` + AIContextAvailable types.Bool `tfsdk:"ai_context_available" json:"ai_context_available,computed"` + Available types.Bool `tfsdk:"available" json:"available,computed"` } diff --git a/internal/services/zero_trust_dlp_entry/schema.go b/internal/services/zero_trust_dlp_entry/schema.go index 445c055984..c0e52857b6 100644 --- a/internal/services/zero_trust_dlp_entry/schema.go +++ b/internal/services/zero_trust_dlp_entry/schema.go @@ -78,6 +78,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDLPEntryConfidenceModel](ctx), Attributes: map[string]schema.Attribute{ + "ai_context_available": schema.BoolAttribute{ + Computed: true, + }, "available": schema.BoolAttribute{ Description: "Indicates whether this entry can be made more or less sensitive by setting a confidence threshold.\nProfiles that use an entry with `available` set to true can use confidence thresholds", Computed: true, diff --git a/internal/services/zero_trust_dlp_predefined_profile/data_source_model.go b/internal/services/zero_trust_dlp_predefined_profile/data_source_model.go index c4c77f9748..691a8587f2 100644 --- a/internal/services/zero_trust_dlp_predefined_profile/data_source_model.go +++ b/internal/services/zero_trust_dlp_predefined_profile/data_source_model.go @@ -21,6 +21,7 @@ type ZeroTrustDLPPredefinedProfileResultDataSourceEnvelope struct { type ZeroTrustDLPPredefinedProfileDataSourceModel struct { AccountID types.String `tfsdk:"account_id" path:"account_id,required"` ProfileID types.String `tfsdk:"profile_id" path:"profile_id,required"` + AIContextEnabled types.Bool `tfsdk:"ai_context_enabled" json:"ai_context_enabled,computed"` AllowedMatchCount types.Int64 `tfsdk:"allowed_match_count" json:"allowed_match_count,computed"` ConfidenceThreshold types.String `tfsdk:"confidence_threshold" json:"confidence_threshold,computed"` CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` @@ -72,5 +73,6 @@ type ZeroTrustDLPPredefinedProfileEntriesPatternDataSourceModel struct { } type ZeroTrustDLPPredefinedProfileEntriesConfidenceDataSourceModel struct { - Available types.Bool `tfsdk:"available" json:"available,computed"` + AIContextAvailable types.Bool `tfsdk:"ai_context_available" json:"ai_context_available,computed"` + Available types.Bool `tfsdk:"available" json:"available,computed"` } diff --git a/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go b/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go index 4f239b5b3c..b7a35b490e 100644 --- a/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go +++ b/internal/services/zero_trust_dlp_predefined_profile/data_source_schema.go @@ -26,6 +26,9 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "profile_id": schema.StringAttribute{ Required: true, }, + "ai_context_enabled": schema.BoolAttribute{ + Computed: true, + }, "allowed_match_count": schema.Int64Attribute{ Description: "Related DLP policies will trigger when the match count exceeds the number set.", Computed: true, @@ -161,6 +164,9 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: customfield.NewNestedObjectType[ZeroTrustDLPPredefinedProfileEntriesConfidenceDataSourceModel](ctx), Attributes: map[string]schema.Attribute{ + "ai_context_available": schema.BoolAttribute{ + Computed: true, + }, "available": schema.BoolAttribute{ Description: "Indicates whether this entry can be made more or less sensitive by setting a confidence threshold.\nProfiles that use an entry with `available` set to true can use confidence thresholds", Computed: true, diff --git a/internal/services/zero_trust_dlp_predefined_profile/model.go b/internal/services/zero_trust_dlp_predefined_profile/model.go index 0ed37c5787..fae782798e 100644 --- a/internal/services/zero_trust_dlp_predefined_profile/model.go +++ b/internal/services/zero_trust_dlp_predefined_profile/model.go @@ -18,6 +18,7 @@ type ZeroTrustDLPPredefinedProfileModel struct { ProfileID types.String `tfsdk:"profile_id" path:"profile_id,required"` AccountID types.String `tfsdk:"account_id" path:"account_id,required"` Entries *[]*ZeroTrustDLPPredefinedProfileEntriesModel `tfsdk:"entries" json:"entries,required"` + AIContextEnabled types.Bool `tfsdk:"ai_context_enabled" json:"ai_context_enabled,optional"` AllowedMatchCount types.Int64 `tfsdk:"allowed_match_count" json:"allowed_match_count,optional"` ConfidenceThreshold types.String `tfsdk:"confidence_threshold" json:"confidence_threshold,optional"` OCREnabled types.Bool `tfsdk:"ocr_enabled" json:"ocr_enabled,optional"` diff --git a/internal/services/zero_trust_dlp_predefined_profile/schema.go b/internal/services/zero_trust_dlp_predefined_profile/schema.go index 1980bda669..bad7bafeb7 100644 --- a/internal/services/zero_trust_dlp_predefined_profile/schema.go +++ b/internal/services/zero_trust_dlp_predefined_profile/schema.go @@ -45,6 +45,9 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "ai_context_enabled": schema.BoolAttribute{ + Optional: true, + }, "allowed_match_count": schema.Int64Attribute{ Optional: true, }, diff --git a/internal/services/zero_trust_dns_location/data_source_model.go b/internal/services/zero_trust_dns_location/data_source_model.go index 562a82f81a..398461b4b0 100644 --- a/internal/services/zero_trust_dns_location/data_source_model.go +++ b/internal/services/zero_trust_dns_location/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustDNSLocationResultDataSourceEnvelope struct { Result ZeroTrustDNSLocationDataSourceModel `json:"result,computed"` } -type ZeroTrustDNSLocationResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustDNSLocationDataSourceModel] `json:"result,computed"` -} - type ZeroTrustDNSLocationDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` LocationID types.String `tfsdk:"location_id" path:"location_id,optional"` diff --git a/internal/services/zero_trust_gateway_certificate/data_source_model.go b/internal/services/zero_trust_gateway_certificate/data_source_model.go index 37b78e5e7d..7d670e5048 100644 --- a/internal/services/zero_trust_gateway_certificate/data_source_model.go +++ b/internal/services/zero_trust_gateway_certificate/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustGatewayCertificateResultDataSourceEnvelope struct { Result ZeroTrustGatewayCertificateDataSourceModel `json:"result,computed"` } -type ZeroTrustGatewayCertificateResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustGatewayCertificateDataSourceModel] `json:"result,computed"` -} - type ZeroTrustGatewayCertificateDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` CertificateID types.String `tfsdk:"certificate_id" path:"certificate_id,optional"` diff --git a/internal/services/zero_trust_gateway_logging/data_source.go b/internal/services/zero_trust_gateway_logging/data_source.go new file mode 100644 index 0000000000..8793c395dc --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/data_source.go @@ -0,0 +1,87 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type ZeroTrustGatewayLoggingDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*ZeroTrustGatewayLoggingDataSource)(nil) + +func NewZeroTrustGatewayLoggingDataSource() datasource.DataSource { + return &ZeroTrustGatewayLoggingDataSource{} +} + +func (d *ZeroTrustGatewayLoggingDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_gateway_logging" +} + +func (d *ZeroTrustGatewayLoggingDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *ZeroTrustGatewayLoggingDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *ZeroTrustGatewayLoggingDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ZeroTrustGatewayLoggingResultDataSourceEnvelope{*data} + _, err := d.client.ZeroTrust.Gateway.Logging.Get( + ctx, + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/zero_trust_gateway_logging/data_source_model.go b/internal/services/zero_trust_gateway_logging/data_source_model.go new file mode 100644 index 0000000000..1b099036e3 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/data_source_model.go @@ -0,0 +1,38 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustGatewayLoggingResultDataSourceEnvelope struct { + Result ZeroTrustGatewayLoggingDataSourceModel `json:"result,computed"` +} + +type ZeroTrustGatewayLoggingDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + RedactPii types.Bool `tfsdk:"redact_pii" json:"redact_pii,computed"` + SettingsByRuleType customfield.NestedObject[ZeroTrustGatewayLoggingSettingsByRuleTypeDataSourceModel] `tfsdk:"settings_by_rule_type" json:"settings_by_rule_type,computed"` +} + +func (m *ZeroTrustGatewayLoggingDataSourceModel) toReadParams(_ context.Context) (params zero_trust.GatewayLoggingGetParams, diags diag.Diagnostics) { + params = zero_trust.GatewayLoggingGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} + +type ZeroTrustGatewayLoggingSettingsByRuleTypeDataSourceModel struct { + DNS jsontypes.Normalized `tfsdk:"dns" json:"dns,computed"` + HTTP jsontypes.Normalized `tfsdk:"http" json:"http,computed"` + L4 jsontypes.Normalized `tfsdk:"l4" json:"l4,computed"` +} diff --git a/internal/services/zero_trust_gateway_logging/data_source_schema.go b/internal/services/zero_trust_gateway_logging/data_source_schema.go new file mode 100644 index 0000000000..00e9d973c3 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/data_source_schema.go @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustGatewayLoggingDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Required: true, + }, + "redact_pii": schema.BoolAttribute{ + Description: "Redact personally identifiable information from activity logging (PII fields are: source IP, user email, user ID, device ID, URL, referrer, user agent).", + Computed: true, + }, + "settings_by_rule_type": schema.SingleNestedAttribute{ + Description: "Logging settings by rule type.", + Computed: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustGatewayLoggingSettingsByRuleTypeDataSourceModel](ctx), + Attributes: map[string]schema.Attribute{ + "dns": schema.StringAttribute{ + Description: "Logging settings for DNS firewall.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + "http": schema.StringAttribute{ + Description: "Logging settings for HTTP/HTTPS firewall.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + "l4": schema.StringAttribute{ + Description: "Logging settings for Network firewall.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + }, + }, + }, + } +} + +func (d *ZeroTrustGatewayLoggingDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *ZeroTrustGatewayLoggingDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/zero_trust_gateway_logging/data_source_schema_test.go b/internal/services/zero_trust_gateway_logging/data_source_schema_test.go new file mode 100644 index 0000000000..213c95da3d --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_logging" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustGatewayLoggingDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_gateway_logging.ZeroTrustGatewayLoggingDataSourceModel)(nil) + schema := zero_trust_gateway_logging.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_gateway_logging/migrations.go b/internal/services/zero_trust_gateway_logging/migrations.go new file mode 100644 index 0000000000..fec906f784 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/migrations.go @@ -0,0 +1,15 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +var _ resource.ResourceWithUpgradeState = (*ZeroTrustGatewayLoggingResource)(nil) + +func (r *ZeroTrustGatewayLoggingResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { + return map[int64]resource.StateUpgrader{} +} diff --git a/internal/services/zero_trust_gateway_logging/model.go b/internal/services/zero_trust_gateway_logging/model.go new file mode 100644 index 0000000000..d6a81bf157 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/model.go @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustGatewayLoggingResultEnvelope struct { + Result ZeroTrustGatewayLoggingModel `json:"result"` +} + +type ZeroTrustGatewayLoggingModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + RedactPii types.Bool `tfsdk:"redact_pii" json:"redact_pii,optional"` + SettingsByRuleType customfield.NestedObject[ZeroTrustGatewayLoggingSettingsByRuleTypeModel] `tfsdk:"settings_by_rule_type" json:"settings_by_rule_type,computed_optional"` +} + +func (m ZeroTrustGatewayLoggingModel) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(m) +} + +func (m ZeroTrustGatewayLoggingModel) MarshalJSONForUpdate(state ZeroTrustGatewayLoggingModel) (data []byte, err error) { + return apijson.MarshalForUpdate(m, state) +} + +type ZeroTrustGatewayLoggingSettingsByRuleTypeModel struct { + DNS jsontypes.Normalized `tfsdk:"dns" json:"dns,optional"` + HTTP jsontypes.Normalized `tfsdk:"http" json:"http,optional"` + L4 jsontypes.Normalized `tfsdk:"l4" json:"l4,optional"` +} diff --git a/internal/services/zero_trust_gateway_logging/resource.go b/internal/services/zero_trust_gateway_logging/resource.go new file mode 100644 index 0000000000..cf8b8e6ea3 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/resource.go @@ -0,0 +1,202 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/resource" +) + +// Ensure provider defined types fully satisfy framework interfaces. +var _ resource.ResourceWithConfigure = (*ZeroTrustGatewayLoggingResource)(nil) +var _ resource.ResourceWithModifyPlan = (*ZeroTrustGatewayLoggingResource)(nil) + +func NewResource() resource.Resource { + return &ZeroTrustGatewayLoggingResource{} +} + +// ZeroTrustGatewayLoggingResource defines the resource implementation. +type ZeroTrustGatewayLoggingResource struct { + client *cloudflare.Client +} + +func (r *ZeroTrustGatewayLoggingResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_gateway_logging" +} + +func (r *ZeroTrustGatewayLoggingResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} + +func (r *ZeroTrustGatewayLoggingResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *ZeroTrustGatewayLoggingModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSON() + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := ZeroTrustGatewayLoggingResultEnvelope{*data} + _, err = r.client.ZeroTrust.Gateway.Logging.Update( + ctx, + zero_trust.GatewayLoggingUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustGatewayLoggingResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *ZeroTrustGatewayLoggingModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + var state *ZeroTrustGatewayLoggingModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + if resp.Diagnostics.HasError() { + return + } + + dataBytes, err := data.MarshalJSONForUpdate(*state) + if err != nil { + resp.Diagnostics.AddError("failed to serialize http request", err.Error()) + return + } + res := new(http.Response) + env := ZeroTrustGatewayLoggingResultEnvelope{*data} + _, err = r.client.ZeroTrust.Gateway.Logging.Update( + ctx, + zero_trust.GatewayLoggingUpdateParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithRequestBody("application/json", dataBytes), + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustGatewayLoggingResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *ZeroTrustGatewayLoggingModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ZeroTrustGatewayLoggingResultEnvelope{*data} + _, err := r.client.ZeroTrust.Gateway.Logging.Get( + ctx, + zero_trust.GatewayLoggingGetParams{ + AccountID: cloudflare.F(data.AccountID.ValueString()), + }, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if res != nil && res.StatusCode == 404 { + resp.Diagnostics.AddWarning("Resource not found", "The resource was not found on the server and will be removed from state.") + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ZeroTrustGatewayLoggingResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + +} + +func (r *ZeroTrustGatewayLoggingResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if req.State.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "This resource cannot be destroyed from Terraform. If you create this resource, it will be "+ + "present in the API until manually deleted.", + ) + } + if req.Plan.Raw.IsNull() { + resp.Diagnostics.AddWarning( + "Resource Destruction Considerations", + "Applying this resource destruction will remove the resource from the Terraform state "+ + "but will not change it in the API. If you would like to destroy or reset this resource "+ + "in the API, refer to the documentation for how to do it manually.", + ) + } +} diff --git a/internal/services/zero_trust_gateway_logging/resource_schema_test.go b/internal/services/zero_trust_gateway_logging/resource_schema_test.go new file mode 100644 index 0000000000..43e28ec9ad --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/resource_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_gateway_logging" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustGatewayLoggingModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_gateway_logging.ZeroTrustGatewayLoggingModel)(nil) + schema := zero_trust_gateway_logging.ResourceSchema(context.TODO()) + errs := test_helpers.ValidateResourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_gateway_logging/schema.go b/internal/services/zero_trust_gateway_logging/schema.go new file mode 100644 index 0000000000..0ff62b04d9 --- /dev/null +++ b/internal/services/zero_trust_gateway_logging/schema.go @@ -0,0 +1,66 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_gateway_logging + +import ( + "context" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" +) + +var _ resource.ResourceWithConfigValidators = (*ZeroTrustGatewayLoggingResource)(nil) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "redact_pii": schema.BoolAttribute{ + Description: "Redact personally identifiable information from activity logging (PII fields are: source IP, user email, user ID, device ID, URL, referrer, user agent).", + Optional: true, + PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}, + }, + "settings_by_rule_type": schema.SingleNestedAttribute{ + Description: "Logging settings by rule type.", + Computed: true, + Optional: true, + CustomType: customfield.NewNestedObjectType[ZeroTrustGatewayLoggingSettingsByRuleTypeModel](ctx), + Attributes: map[string]schema.Attribute{ + "dns": schema.StringAttribute{ + Description: "Logging settings for DNS firewall.", + Optional: true, + CustomType: jsontypes.NormalizedType{}, + }, + "http": schema.StringAttribute{ + Description: "Logging settings for HTTP/HTTPS firewall.", + Optional: true, + CustomType: jsontypes.NormalizedType{}, + }, + "l4": schema.StringAttribute{ + Description: "Logging settings for Network firewall.", + Optional: true, + CustomType: jsontypes.NormalizedType{}, + }, + }, + PlanModifiers: []planmodifier.Object{objectplanmodifier.RequiresReplace()}, + }, + }, + } +} + +func (r *ZeroTrustGatewayLoggingResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) +} + +func (r *ZeroTrustGatewayLoggingResource) ConfigValidators(_ context.Context) []resource.ConfigValidator { + return []resource.ConfigValidator{} +} diff --git a/internal/services/zero_trust_gateway_policy/data_source_model.go b/internal/services/zero_trust_gateway_policy/data_source_model.go index b4f4b1a9be..ef178cb0bc 100644 --- a/internal/services/zero_trust_gateway_policy/data_source_model.go +++ b/internal/services/zero_trust_gateway_policy/data_source_model.go @@ -17,10 +17,6 @@ type ZeroTrustGatewayPolicyResultDataSourceEnvelope struct { Result ZeroTrustGatewayPolicyDataSourceModel `json:"result,computed"` } -type ZeroTrustGatewayPolicyResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustGatewayPolicyDataSourceModel] `json:"result,computed"` -} - type ZeroTrustGatewayPolicyDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RuleID types.String `tfsdk:"rule_id" path:"rule_id,optional"` diff --git a/internal/services/zero_trust_gateway_policy/model.go b/internal/services/zero_trust_gateway_policy/model.go index a178a93486..eed6d62eb8 100644 --- a/internal/services/zero_trust_gateway_policy/model.go +++ b/internal/services/zero_trust_gateway_policy/model.go @@ -143,7 +143,7 @@ type ZeroTrustGatewayPolicyRuleSettingsQuarantineModel struct { } type ZeroTrustGatewayPolicyRuleSettingsResolveDNSInternallyModel struct { - Fallback types.String `tfsdk:"fallback" json:"fallback,optional"` + Fallback types.String `tfsdk:"fallback" json:"fallback,computed_optional"` ViewID types.String `tfsdk:"view_id" json:"view_id,optional"` } diff --git a/internal/services/zero_trust_gateway_policy/schema.go b/internal/services/zero_trust_gateway_policy/schema.go index 2a1e2a2771..f641d3c7fa 100644 --- a/internal/services/zero_trust_gateway_policy/schema.go +++ b/internal/services/zero_trust_gateway_policy/schema.go @@ -456,10 +456,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { Attributes: map[string]schema.Attribute{ "fallback": schema.StringAttribute{ Description: "The fallback behavior to apply when the internal DNS response code is different from 'NOERROR' or when the response data only contains CNAME records for 'A' or 'AAAA' queries.", + Computed: true, Optional: true, Validators: []validator.String{ stringvalidator.OneOfCaseInsensitive("none", "public_dns"), }, + Default: stringdefault.StaticString("none"), }, "view_id": schema.StringAttribute{ Description: "The internal DNS view identifier that's passed to the internal DNS service.", diff --git a/internal/services/zero_trust_gateway_proxy_endpoint/data_source_model.go b/internal/services/zero_trust_gateway_proxy_endpoint/data_source_model.go index b52a3894fb..bddc81ed18 100644 --- a/internal/services/zero_trust_gateway_proxy_endpoint/data_source_model.go +++ b/internal/services/zero_trust_gateway_proxy_endpoint/data_source_model.go @@ -7,6 +7,8 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -16,8 +18,14 @@ type ZeroTrustGatewayProxyEndpointResultDataSourceEnvelope struct { } type ZeroTrustGatewayProxyEndpointDataSourceModel struct { - AccountID types.String `tfsdk:"account_id" path:"account_id,required"` - ProxyEndpointID types.String `tfsdk:"proxy_endpoint_id" path:"proxy_endpoint_id,required"` + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + ProxyEndpointID types.String `tfsdk:"proxy_endpoint_id" path:"proxy_endpoint_id,required"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at" json:"created_at,computed" format:"date-time"` + ID types.String `tfsdk:"id" json:"id,computed"` + Name types.String `tfsdk:"name" json:"name,computed"` + Subdomain types.String `tfsdk:"subdomain" json:"subdomain,computed"` + UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at" json:"updated_at,computed" format:"date-time"` + IPs customfield.List[types.String] `tfsdk:"ips" json:"ips,computed"` } func (m *ZeroTrustGatewayProxyEndpointDataSourceModel) toReadParams(_ context.Context) (params zero_trust.GatewayProxyEndpointGetParams, diags diag.Diagnostics) { diff --git a/internal/services/zero_trust_gateway_proxy_endpoint/data_source_schema.go b/internal/services/zero_trust_gateway_proxy_endpoint/data_source_schema.go index d33276d62b..a28fc53726 100644 --- a/internal/services/zero_trust_gateway_proxy_endpoint/data_source_schema.go +++ b/internal/services/zero_trust_gateway_proxy_endpoint/data_source_schema.go @@ -5,8 +5,11 @@ package zero_trust_gateway_proxy_endpoint import ( "context" + "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" ) var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustGatewayProxyEndpointDataSource)(nil) @@ -20,6 +23,31 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "proxy_endpoint_id": schema.StringAttribute{ Required: true, }, + "created_at": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "id": schema.StringAttribute{ + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "The name of the proxy endpoint.", + Computed: true, + }, + "subdomain": schema.StringAttribute{ + Description: "The subdomain to be used as the destination in the proxy client.", + Computed: true, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "ips": schema.ListAttribute{ + Description: "A list of CIDRs to restrict ingress connections.", + Computed: true, + CustomType: customfield.NewListType[types.String](ctx), + ElementType: types.StringType, + }, }, } } diff --git a/internal/services/zero_trust_list/data_source.go b/internal/services/zero_trust_list/data_source.go index 09393344c1..691becb922 100644 --- a/internal/services/zero_trust_list/data_source.go +++ b/internal/services/zero_trust_list/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustListDataSource) Read(ctx context.Context, req datasource.ReadR return } - env := ZeroTrustListResultListDataSourceEnvelope{} + env := ZeroTrustListsResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Gateway.Lists.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustListDataSource) Read(ctx context.Context, req datasource.ReadR } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.ListID = ts[0].ListID + data.ListID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_list/data_source_model.go b/internal/services/zero_trust_list/data_source_model.go index 214bac8f72..7e36de37b7 100644 --- a/internal/services/zero_trust_list/data_source_model.go +++ b/internal/services/zero_trust_list/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustListResultDataSourceEnvelope struct { Result ZeroTrustListDataSourceModel `json:"result,computed"` } -type ZeroTrustListResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustListDataSourceModel] `json:"result,computed"` -} - type ZeroTrustListDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ListID types.String `tfsdk:"list_id" path:"list_id,optional"` diff --git a/internal/services/zero_trust_risk_scoring_integration/data_source_model.go b/internal/services/zero_trust_risk_scoring_integration/data_source_model.go index 3506046d37..ff2c2aa149 100644 --- a/internal/services/zero_trust_risk_scoring_integration/data_source_model.go +++ b/internal/services/zero_trust_risk_scoring_integration/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustRiskScoringIntegrationResultDataSourceEnvelope struct { Result ZeroTrustRiskScoringIntegrationDataSourceModel `json:"result,computed"` } -type ZeroTrustRiskScoringIntegrationResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustRiskScoringIntegrationDataSourceModel] `json:"result,computed"` -} - type ZeroTrustRiskScoringIntegrationDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` IntegrationID types.String `tfsdk:"integration_id" path:"integration_id,optional"` diff --git a/internal/services/zero_trust_tunnel_cloudflared/data_source.go b/internal/services/zero_trust_tunnel_cloudflared/data_source.go index b0a066b92d..77eed5f3cb 100644 --- a/internal/services/zero_trust_tunnel_cloudflared/data_source.go +++ b/internal/services/zero_trust_tunnel_cloudflared/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustTunnelCloudflaredDataSource) Read(ctx context.Context, req dat return } - env := ZeroTrustTunnelCloudflaredResultListDataSourceEnvelope{} + env := ZeroTrustTunnelCloudflaredsResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Tunnels.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustTunnelCloudflaredDataSource) Read(ctx context.Context, req dat } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.TunnelID = ts[0].TunnelID + data.TunnelID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_tunnel_cloudflared/data_source_model.go b/internal/services/zero_trust_tunnel_cloudflared/data_source_model.go index c3323a11ea..662c8bf0fc 100644 --- a/internal/services/zero_trust_tunnel_cloudflared/data_source_model.go +++ b/internal/services/zero_trust_tunnel_cloudflared/data_source_model.go @@ -18,10 +18,6 @@ type ZeroTrustTunnelCloudflaredResultDataSourceEnvelope struct { Result ZeroTrustTunnelCloudflaredDataSourceModel `json:"result,computed"` } -type ZeroTrustTunnelCloudflaredResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustTunnelCloudflaredDataSourceModel] `json:"result,computed"` -} - type ZeroTrustTunnelCloudflaredDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` TunnelID types.String `tfsdk:"tunnel_id" path:"tunnel_id,optional"` diff --git a/internal/services/zero_trust_tunnel_cloudflared_route/data_source.go b/internal/services/zero_trust_tunnel_cloudflared_route/data_source.go index fc6e50062f..d3c03fc27d 100644 --- a/internal/services/zero_trust_tunnel_cloudflared_route/data_source.go +++ b/internal/services/zero_trust_tunnel_cloudflared_route/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustTunnelCloudflaredRouteDataSource) Read(ctx context.Context, re return } - env := ZeroTrustTunnelCloudflaredRouteResultListDataSourceEnvelope{} + env := ZeroTrustTunnelCloudflaredRoutesResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Networks.Routes.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustTunnelCloudflaredRouteDataSource) Read(ctx context.Context, re } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.RouteID = ts[0].RouteID + data.RouteID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_tunnel_cloudflared_route/data_source_model.go b/internal/services/zero_trust_tunnel_cloudflared_route/data_source_model.go index 4835a04368..0e8cb3843b 100644 --- a/internal/services/zero_trust_tunnel_cloudflared_route/data_source_model.go +++ b/internal/services/zero_trust_tunnel_cloudflared_route/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustTunnelCloudflaredRouteResultDataSourceEnvelope struct { Result ZeroTrustTunnelCloudflaredRouteDataSourceModel `json:"result,computed"` } -type ZeroTrustTunnelCloudflaredRouteResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustTunnelCloudflaredRouteDataSourceModel] `json:"result,computed"` -} - type ZeroTrustTunnelCloudflaredRouteDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` RouteID types.String `tfsdk:"route_id" path:"route_id,optional"` diff --git a/internal/services/zero_trust_tunnel_cloudflared_token/data_source.go b/internal/services/zero_trust_tunnel_cloudflared_token/data_source.go new file mode 100644 index 0000000000..2508d98b77 --- /dev/null +++ b/internal/services/zero_trust_tunnel_cloudflared_token/data_source.go @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_cloudflared_token + +import ( + "context" + "fmt" + "io" + "net/http" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/option" + "github.com/cloudflare/terraform-provider-cloudflare/internal/apijson" + "github.com/cloudflare/terraform-provider-cloudflare/internal/logging" + "github.com/hashicorp/terraform-plugin-framework/datasource" +) + +type ZeroTrustTunnelCloudflaredTokenDataSource struct { + client *cloudflare.Client +} + +var _ datasource.DataSourceWithConfigure = (*ZeroTrustTunnelCloudflaredTokenDataSource)(nil) + +func NewZeroTrustTunnelCloudflaredTokenDataSource() datasource.DataSource { + return &ZeroTrustTunnelCloudflaredTokenDataSource{} +} + +func (d *ZeroTrustTunnelCloudflaredTokenDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_zero_trust_tunnel_cloudflared_token" +} + +func (d *ZeroTrustTunnelCloudflaredTokenDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*cloudflare.Client) + + if !ok { + resp.Diagnostics.AddError( + "unexpected resource configure type", + fmt.Sprintf("Expected *cloudflare.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + d.client = client +} + +func (d *ZeroTrustTunnelCloudflaredTokenDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data *ZeroTrustTunnelCloudflaredTokenDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + params, diags := data.toReadParams(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + res := new(http.Response) + env := ZeroTrustTunnelCloudflaredTokenResultDataSourceEnvelope{*data} + _, err := d.client.ZeroTrust.Tunnels.Token.Get( + ctx, + data.TunnelID.ValueString(), + params, + option.WithResponseBodyInto(&res), + option.WithMiddleware(logging.Middleware(ctx)), + ) + if err != nil { + resp.Diagnostics.AddError("failed to make http request", err.Error()) + return + } + bytes, _ := io.ReadAll(res.Body) + err = apijson.UnmarshalComputed(bytes, &env) + if err != nil { + resp.Diagnostics.AddError("failed to deserialize http request", err.Error()) + return + } + data = &env.Result + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/services/zero_trust_tunnel_cloudflared_token/data_source_model.go b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_model.go new file mode 100644 index 0000000000..af20bc3ff4 --- /dev/null +++ b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_model.go @@ -0,0 +1,29 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_cloudflared_token + +import ( + "context" + + "github.com/cloudflare/cloudflare-go/v4" + "github.com/cloudflare/cloudflare-go/v4/zero_trust" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ZeroTrustTunnelCloudflaredTokenResultDataSourceEnvelope struct { + Result ZeroTrustTunnelCloudflaredTokenDataSourceModel `json:"result,computed"` +} + +type ZeroTrustTunnelCloudflaredTokenDataSourceModel struct { + AccountID types.String `tfsdk:"account_id" path:"account_id,required"` + TunnelID types.String `tfsdk:"tunnel_id" path:"tunnel_id,required"` +} + +func (m *ZeroTrustTunnelCloudflaredTokenDataSourceModel) toReadParams(_ context.Context) (params zero_trust.TunnelTokenGetParams, diags diag.Diagnostics) { + params = zero_trust.TunnelTokenGetParams{ + AccountID: cloudflare.F(m.AccountID.ValueString()), + } + + return +} diff --git a/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema.go b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema.go new file mode 100644 index 0000000000..8874d9ddfc --- /dev/null +++ b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema.go @@ -0,0 +1,35 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_cloudflared_token + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +var _ datasource.DataSourceWithConfigValidators = (*ZeroTrustTunnelCloudflaredTokenDataSource)(nil) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "account_id": schema.StringAttribute{ + Description: "Cloudflare account ID", + Required: true, + }, + "tunnel_id": schema.StringAttribute{ + Description: "UUID of the tunnel.", + Required: true, + }, + }, + } +} + +func (d *ZeroTrustTunnelCloudflaredTokenDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *ZeroTrustTunnelCloudflaredTokenDataSource) ConfigValidators(_ context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{} +} diff --git a/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema_test.go b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema_test.go new file mode 100644 index 0000000000..61112802ae --- /dev/null +++ b/internal/services/zero_trust_tunnel_cloudflared_token/data_source_schema_test.go @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +package zero_trust_tunnel_cloudflared_token_test + +import ( + "context" + "testing" + + "github.com/cloudflare/terraform-provider-cloudflare/internal/services/zero_trust_tunnel_cloudflared_token" + "github.com/cloudflare/terraform-provider-cloudflare/internal/test_helpers" +) + +func TestZeroTrustTunnelCloudflaredTokenDataSourceModelSchemaParity(t *testing.T) { + t.Parallel() + model := (*zero_trust_tunnel_cloudflared_token.ZeroTrustTunnelCloudflaredTokenDataSourceModel)(nil) + schema := zero_trust_tunnel_cloudflared_token.DataSourceSchema(context.TODO()) + errs := test_helpers.ValidateDataSourceModelSchemaIntegrity(model, schema) + errs.Report(t) +} diff --git a/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source.go b/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source.go index f89b05d5bc..0a499e4d33 100644 --- a/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source.go +++ b/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source.go @@ -64,7 +64,7 @@ func (d *ZeroTrustTunnelCloudflaredVirtualNetworkDataSource) Read(ctx context.Co return } - env := ZeroTrustTunnelCloudflaredVirtualNetworkResultListDataSourceEnvelope{} + env := ZeroTrustTunnelCloudflaredVirtualNetworksResultListDataSourceEnvelope{} page, err := d.client.ZeroTrust.Networks.VirtualNetworks.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZeroTrustTunnelCloudflaredVirtualNetworkDataSource) Read(ctx context.Co } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.VirtualNetworkID = ts[0].VirtualNetworkID + data.VirtualNetworkID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source_model.go b/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source_model.go index a2cab7ef70..c547100fc7 100644 --- a/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source_model.go +++ b/internal/services/zero_trust_tunnel_cloudflared_virtual_network/data_source_model.go @@ -7,7 +7,6 @@ import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/zero_trust" - "github.com/cloudflare/terraform-provider-cloudflare/internal/customfield" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -17,10 +16,6 @@ type ZeroTrustTunnelCloudflaredVirtualNetworkResultDataSourceEnvelope struct { Result ZeroTrustTunnelCloudflaredVirtualNetworkDataSourceModel `json:"result,computed"` } -type ZeroTrustTunnelCloudflaredVirtualNetworkResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZeroTrustTunnelCloudflaredVirtualNetworkDataSourceModel] `json:"result,computed"` -} - type ZeroTrustTunnelCloudflaredVirtualNetworkDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` VirtualNetworkID types.String `tfsdk:"virtual_network_id" path:"virtual_network_id,optional"` diff --git a/internal/services/zone/data_source.go b/internal/services/zone/data_source.go index d0fbdc93ff..d06d8a40c2 100644 --- a/internal/services/zone/data_source.go +++ b/internal/services/zone/data_source.go @@ -64,7 +64,7 @@ func (d *ZoneDataSource) Read(ctx context.Context, req datasource.ReadRequest, r return } - env := ZoneResultListDataSourceEnvelope{} + env := ZonesResultListDataSourceEnvelope{} page, err := d.client.Zones.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZoneDataSource) Read(ctx context.Context, req datasource.ReadRequest, r } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.ZoneID = ts[0].ZoneID + data.ZoneID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zone/data_source_model.go b/internal/services/zone/data_source_model.go index f7b3c12af4..f8d774958d 100644 --- a/internal/services/zone/data_source_model.go +++ b/internal/services/zone/data_source_model.go @@ -17,10 +17,6 @@ type ZoneResultDataSourceEnvelope struct { Result ZoneDataSourceModel `json:"result,computed"` } -type ZoneResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZoneDataSourceModel] `json:"result,computed"` -} - type ZoneDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` ZoneID types.String `tfsdk:"zone_id" path:"zone_id,optional"` @@ -34,6 +30,7 @@ type ZoneDataSourceModel struct { Paused types.Bool `tfsdk:"paused" json:"paused,computed"` Status types.String `tfsdk:"status" json:"status,computed"` Type types.String `tfsdk:"type" json:"type,computed"` + VerificationKey types.String `tfsdk:"verification_key" json:"verification_key,computed"` NameServers customfield.List[types.String] `tfsdk:"name_servers" json:"name_servers,computed"` OriginalNameServers customfield.List[types.String] `tfsdk:"original_name_servers" json:"original_name_servers,computed"` VanityNameServers customfield.List[types.String] `tfsdk:"vanity_name_servers" json:"vanity_name_servers,computed"` diff --git a/internal/services/zone/data_source_schema.go b/internal/services/zone/data_source_schema.go index 577a9459b0..678b81fbc6 100644 --- a/internal/services/zone/data_source_schema.go +++ b/internal/services/zone/data_source_schema.go @@ -87,6 +87,10 @@ func DataSourceSchema(ctx context.Context) schema.Schema { ), }, }, + "verification_key": schema.StringAttribute{ + Description: "Verification key for partial zone setup.", + Computed: true, + }, "name_servers": schema.ListAttribute{ Description: "The name servers Cloudflare assigns to a zone", Computed: true, diff --git a/internal/services/zone/list_data_source_model.go b/internal/services/zone/list_data_source_model.go index ab75820f27..d426abacb7 100644 --- a/internal/services/zone/list_data_source_model.go +++ b/internal/services/zone/list_data_source_model.go @@ -83,6 +83,7 @@ type ZonesResultDataSourceModel struct { Status types.String `tfsdk:"status" json:"status,computed"` Type types.String `tfsdk:"type" json:"type,computed"` VanityNameServers customfield.List[types.String] `tfsdk:"vanity_name_servers" json:"vanity_name_servers,computed"` + VerificationKey types.String `tfsdk:"verification_key" json:"verification_key,computed"` } type ZonesMetaDataSourceModel struct { diff --git a/internal/services/zone/list_data_source_schema.go b/internal/services/zone/list_data_source_schema.go index f725cc83d1..77ea247493 100644 --- a/internal/services/zone/list_data_source_schema.go +++ b/internal/services/zone/list_data_source_schema.go @@ -237,6 +237,10 @@ func ListDataSourceSchema(ctx context.Context) schema.Schema { CustomType: customfield.NewListType[types.String](ctx), ElementType: types.StringType, }, + "verification_key": schema.StringAttribute{ + Description: "Verification key for partial zone setup.", + Computed: true, + }, }, }, }, diff --git a/internal/services/zone/model.go b/internal/services/zone/model.go index ec1427dba6..cad02b2f69 100644 --- a/internal/services/zone/model.go +++ b/internal/services/zone/model.go @@ -27,6 +27,7 @@ type ZoneModel struct { OriginalRegistrar types.String `tfsdk:"original_registrar" json:"original_registrar,computed"` Paused types.Bool `tfsdk:"paused" json:"paused,computed"` Status types.String `tfsdk:"status" json:"status,computed"` + VerificationKey types.String `tfsdk:"verification_key" json:"verification_key,computed"` NameServers customfield.List[types.String] `tfsdk:"name_servers" json:"name_servers,computed"` OriginalNameServers customfield.List[types.String] `tfsdk:"original_name_servers" json:"original_name_servers,computed"` Meta customfield.NestedObject[ZoneMetaModel] `tfsdk:"meta" json:"meta,computed"` diff --git a/internal/services/zone/schema.go b/internal/services/zone/schema.go index a22dd587db..c2618603b3 100644 --- a/internal/services/zone/schema.go +++ b/internal/services/zone/schema.go @@ -106,6 +106,10 @@ func ResourceSchema(ctx context.Context) schema.Schema { ), }, }, + "verification_key": schema.StringAttribute{ + Description: "Verification key for partial zone setup.", + Computed: true, + }, "name_servers": schema.ListAttribute{ Description: "The name servers Cloudflare assigns to a zone", Computed: true, diff --git a/internal/services/zone_cache_reserve/data_source_model.go b/internal/services/zone_cache_reserve/data_source_model.go index 9ea534de42..505e445113 100644 --- a/internal/services/zone_cache_reserve/data_source_model.go +++ b/internal/services/zone_cache_reserve/data_source_model.go @@ -17,11 +17,11 @@ type ZoneCacheReserveResultDataSourceEnvelope struct { } type ZoneCacheReserveDataSourceModel struct { - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Editable types.Bool `tfsdk:"editable" json:"editable,computed"` - ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` - Value types.String `tfsdk:"value" json:"value,computed"` - ZoneSettingID types.String `tfsdk:"zone_setting_id" json:"id,computed"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Editable types.Bool `tfsdk:"editable" json:"editable,computed"` + ID types.String `tfsdk:"id" json:"id,computed"` + ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` + Value types.String `tfsdk:"value" json:"value,computed"` } func (m *ZoneCacheReserveDataSourceModel) toReadParams(_ context.Context) (params cache.CacheReserveGetParams, diags diag.Diagnostics) { diff --git a/internal/services/zone_cache_reserve/data_source_schema.go b/internal/services/zone_cache_reserve/data_source_schema.go index c79f506e94..534724281d 100644 --- a/internal/services/zone_cache_reserve/data_source_schema.go +++ b/internal/services/zone_cache_reserve/data_source_schema.go @@ -25,6 +25,13 @@ func DataSourceSchema(ctx context.Context) schema.Schema { Description: "Whether the setting is editable", Computed: true, }, + "id": schema.StringAttribute{ + Description: "ID of the zone setting.", + Computed: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive("cache_reserve"), + }, + }, "modified_on": schema.StringAttribute{ Description: "Last time this setting was modified.", Computed: true, @@ -37,13 +44,6 @@ func DataSourceSchema(ctx context.Context) schema.Schema { stringvalidator.OneOfCaseInsensitive("on", "off"), }, }, - "zone_setting_id": schema.StringAttribute{ - Description: "ID of the zone setting.", - Computed: true, - Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("cache_reserve"), - }, - }, }, } } diff --git a/internal/services/zone_cache_reserve/model.go b/internal/services/zone_cache_reserve/model.go index 5439020efa..523ec42ec3 100644 --- a/internal/services/zone_cache_reserve/model.go +++ b/internal/services/zone_cache_reserve/model.go @@ -13,12 +13,11 @@ type ZoneCacheReserveResultEnvelope struct { } type ZoneCacheReserveModel struct { - ID types.String `tfsdk:"id" json:"-,computed"` - ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` - Value types.String `tfsdk:"value" json:"value,computed_optional"` - Editable types.Bool `tfsdk:"editable" json:"editable,computed"` - ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` - ZoneSettingID types.String `tfsdk:"zone_setting_id" json:"id,computed"` + ID types.String `tfsdk:"id" json:"-,computed"` + ZoneID types.String `tfsdk:"zone_id" path:"zone_id,required"` + Value types.String `tfsdk:"value" json:"value,computed_optional"` + Editable types.Bool `tfsdk:"editable" json:"editable,computed"` + ModifiedOn timetypes.RFC3339 `tfsdk:"modified_on" json:"modified_on,computed" format:"date-time"` } func (m ZoneCacheReserveModel) MarshalJSON() (data []byte, err error) { diff --git a/internal/services/zone_cache_reserve/schema.go b/internal/services/zone_cache_reserve/schema.go index 2882a9fd50..9f0928cc62 100644 --- a/internal/services/zone_cache_reserve/schema.go +++ b/internal/services/zone_cache_reserve/schema.go @@ -48,13 +48,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, CustomType: timetypes.RFC3339Type{}, }, - "zone_setting_id": schema.StringAttribute{ - Description: "ID of the zone setting.", - Computed: true, - Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive("cache_reserve"), - }, - }, }, } } diff --git a/internal/services/zone_lockdown/data_source.go b/internal/services/zone_lockdown/data_source.go index d8a539ef00..b53a1541b8 100644 --- a/internal/services/zone_lockdown/data_source.go +++ b/internal/services/zone_lockdown/data_source.go @@ -64,7 +64,7 @@ func (d *ZoneLockdownDataSource) Read(ctx context.Context, req datasource.ReadRe return } - env := ZoneLockdownResultListDataSourceEnvelope{} + env := ZoneLockdownsResultListDataSourceEnvelope{} page, err := d.client.Firewall.Lockdowns.List(ctx, params) if err != nil { resp.Diagnostics.AddError("failed to make http request", err.Error()) @@ -84,7 +84,7 @@ func (d *ZoneLockdownDataSource) Read(ctx context.Context, req datasource.ReadRe } ts, diags := env.Result.AsStructSliceT(ctx) resp.Diagnostics.Append(diags...) - data.LockDownsID = ts[0].LockDownsID + data.LockDownsID = ts[0].ID } params, diags := data.toReadParams(ctx) diff --git a/internal/services/zone_lockdown/data_source_model.go b/internal/services/zone_lockdown/data_source_model.go index c8d2bd7b44..bac6171fed 100644 --- a/internal/services/zone_lockdown/data_source_model.go +++ b/internal/services/zone_lockdown/data_source_model.go @@ -17,10 +17,6 @@ type ZoneLockdownResultDataSourceEnvelope struct { Result ZoneLockdownDataSourceModel `json:"result,computed"` } -type ZoneLockdownResultListDataSourceEnvelope struct { - Result customfield.NestedObjectList[ZoneLockdownDataSourceModel] `json:"result,computed"` -} - type ZoneLockdownDataSourceModel struct { ID types.String `tfsdk:"id" json:"-,computed"` LockDownsID types.String `tfsdk:"lock_downs_id" path:"lock_downs_id,optional"` diff --git a/internal/services/zone_setting/data_source_schema.go b/internal/services/zone_setting/data_source_schema.go index a418f54a92..6384203e51 100644 --- a/internal/services/zone_setting/data_source_schema.go +++ b/internal/services/zone_setting/data_source_schema.go @@ -74,6 +74,7 @@ func DataSourceSchema(ctx context.Context) schema.Schema { "origin_max_http_version", "polish", "prefetch_preload", + "privacy_pass", "proxy_read_timeout", "pseudo_ipv4", "replace_insecure_js", diff --git a/internal/services/zone_setting/schema.go b/internal/services/zone_setting/schema.go index 6685019e7e..f8da25b77e 100644 --- a/internal/services/zone_setting/schema.go +++ b/internal/services/zone_setting/schema.go @@ -71,6 +71,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "origin_max_http_version", "polish", "prefetch_preload", + "privacy_pass", "proxy_read_timeout", "pseudo_ipv4", "replace_insecure_js", diff --git a/internal/services/zone_subscription/schema.go b/internal/services/zone_subscription/schema.go index 39c4b92e40..f68f6a3cd5 100644 --- a/internal/services/zone_subscription/schema.go +++ b/internal/services/zone_subscription/schema.go @@ -46,6 +46,20 @@ func ResourceSchema(ctx context.Context) schema.Schema { "id": schema.StringAttribute{ Description: "The ID of the rate plan.", Optional: true, + Validators: []validator.String{ + stringvalidator.OneOfCaseInsensitive( + "free", + "lite", + "pro", + "pro_plus", + "business", + "enterprise", + "partners_free", + "partners_pro", + "partners_business", + "partners_enterprise", + ), + }, }, "currency": schema.StringAttribute{ Description: "The currency applied to the rate plan subscription.", diff --git a/internal/version.go b/internal/version.go index 1e49ee485b..c87941c2c8 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.0.1-alpha.0" +const PackageVersion = "5.0.0" // x-release-please-version diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000000..00afa69886 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,63 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "simple" +} \ No newline at end of file diff --git a/scripts/check-release-environment b/scripts/check-release-environment new file mode 100644 index 0000000000..d257db3c3f --- /dev/null +++ b/scripts/check-release-environment @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${GPG_PRIVATE_KEY}" ]; then + errors+=("The GPG_PRIVATE_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +if [ -z "${GPG_PASSPHRASE}" ]; then + errors+=("The GPG_PASSPHRASE secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/scripts/generate-docs b/scripts/generate-docs index 5980032fe0..ac49562426 100755 --- a/scripts/generate-docs +++ b/scripts/generate-docs @@ -4,10 +4,4 @@ set -e cd "$(dirname "$0")/.." -echo "==> Generating Terraform provider documentation" -if ! command -v "tfplugindocs" &> /dev/null -then - go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs -fi - -"$(go env GOPATH)/bin/tfplugindocs" generate -rendered-provider-name "Cloudflare" -provider-name="cloudflare" +# tfplugindocs is disabled. To enable it, set `generate_docs: true` in the provider options. diff --git a/scripts/test b/scripts/test index efebceaee1..f7c3082033 100755 --- a/scripts/test +++ b/scripts/test @@ -4,53 +4,5 @@ set -e cd "$(dirname "$0")/.." -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color - -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -kill_server_on_port() { - pids=$(lsof -t -i tcp:"$1" || echo "") - if [ "$pids" != "" ]; then - kill "$pids" - echo "Stopped $pids." - fi -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if ! is_overriding_api_base_url && ! prism_is_running ; then - # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT - - # Start the dev server - ./scripts/mock --daemon -fi - -if is_overriding_api_base_url ; then - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" - echo - echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo -fi - echo "==> Running tests" go test ./... "$@" diff --git a/templates/guides/migrating-renamed-resources.md b/templates/guides/migrating-renamed-resources.md index 294105d722..5c3a3530d7 100644 --- a/templates/guides/migrating-renamed-resources.md +++ b/templates/guides/migrating-renamed-resources.md @@ -17,7 +17,7 @@ description: Guide for handling renamed resources in the Cloudflare Provider migration. - Make backups of your configuration and state file. -~> It is recommended to do perform testing in a non-production, non-critical +~> It is recommended to perform testing in a non-production, non-critical environment or a small subset resources before performing the changes to all resources. diff --git a/templates/guides/version-5-upgrade.md b/templates/guides/version-5-upgrade.md index c4e7e59878..47106a90cd 100644 --- a/templates/guides/version-5-upgrade.md +++ b/templates/guides/version-5-upgrade.md @@ -42,40 +42,63 @@ provider "cloudflare" { } ``` -## Resource renames +## Approach -For an in depth guide on how to perform migrations for resources or datasources that -have been renamed, check out [migrating renamed resources]. +At a high level, there are two parts to the migration. The first is the migration of the +configuration (HCL) and the second is the migration of the state. Within each of those +sections, there is the need to migrate attributes and potentially the resource rename. -The pattern files for v5 resource renames are: +### Automatic -- `cloudflare_terraform_v5_resource_renames_configuration` -- `cloudflare_terraform_v5_resource_renames_state` +For assisting with automatic migrations, we have provided [GritQL] patterns. -## Automatic migration - -For assisting with automatic migrations, we have provided a [GritQL] pattern. - -This will allow you to rewrite the parts of your Terraform configuration (not state) -that have changed automatically. Once you [install Grit], you can run the following -command in the directory where your Terraform configuration is located. +This will allow you to rewrite the parts of your Terraform configuration and state +that have changed automatically. Once you [install Grit], you can run the commands +in the directory where your Terraform configuration is located. ~> While all efforts have been made to ease the transition, some of the more complex resources that may contain difficult to reconcile resources have been intentionally skipped for the automatic migration and are only manually documented. If you are using modules or other dynamic features of HCL, the provided codemods may not be -as effective. We recommend reviewing the migration notes below to verify all the +as effective. We recommend reviewing the manual migration notes to verify all the changes. -```bash -$ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5 -``` - We recommend ensuring you are using version control for these changes or make a backup prior to initiating the change to enable reverting if needed. +1. Update the resource attributes in your configuration. _Note: this will not update + your state file. The next step will determine how your state file is updated._ + ```bash + $ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5 + ``` +2. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the attribute changes. If you are choosing to + use the provided GritQL patterns, the pattern name is + `cloudflare_terraform_v5_attribute_renames_state`. Otherwise, you can reimport the + resources without manually managing the state file. +3. Perform the resource renames. _Note: this will not update your state file. + The next step will determine how your state file is updated._ + ```bash + $ grit apply github.com/cloudflare/terraform-provider-cloudflare#cloudflare_terraform_v5_resource_renames_configuration + ``` +4. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the resource renames. If you are choosing to + use the provided GritQL patterns, the pattern name is + `cloudflare_terraform_v5_resource_renames_state`. + +### Manual + +1. Update the resource attributes in your configuration using the migration notes. +2. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the attribute changes. +3. Perform the resource renames using the migration notes. +4. Choose the appropriate method from [migrating renamed resources] that best suits + your situation and use case to migrate the resource renames. + +## Changelog + ```grit language hcl @@ -152,7 +175,7 @@ cloudflare_terraform_v5() ## cloudflare_device_settings_policy -- Renamed to `cloudflare_zero_trust_device_profiles` +- Renamed to `cloudflare_zero_trust_device_custom_profile` or `cloudflare_zero_trust_device_custom_profile` depending on your intended usage. ## cloudflare_dlp_custom_profile @@ -166,7 +189,7 @@ cloudflare_terraform_v5() - Renamed to `cloudflare_zero_trust_custom_dlp_profile` or `cloudflare_zero_trust_predefined_dlp_profile` depending on which you are targeting. -## cloudflare_fallback_domain +## cloudflare_fallback_domain / cloudflare_zero_trust_local_fallback_domain - Renamed to `cloudflare_zero_trust_device_custom_profile_local_domain_fallback` or `cloudflare_zero_trust_device_default_profile_local_domain_fallback` depending on which you are targeting. @@ -192,7 +215,7 @@ cloudflare_terraform_v5() ## cloudflare_split_tunnel -- Renamed to `cloudflare_zero_trust_split_tunnels` +- Renamed to `cloudflare_zero_trust_device_default_profile` and `cloudflare_zero_trust_device_custom_profile` depending on which you are targeting. ## cloudflare_static_route @@ -228,11 +251,11 @@ cloudflare_terraform_v5() ## cloudflare_tunnel_route -- Renamed to `cloudflare_zero_trust_tunnel_route` +- Renamed to `cloudflare_zero_trust_tunnel_cloudflared_route` ## cloudflare_tunnel_virtual_network -- Renamed to `cloudflare_zero_trust_tunnel_virtual_network` +- Renamed to `cloudflare_zero_trust_tunnel_cloudflared_virtual_network` ## cloudflare_worker_cron_trigger @@ -254,10 +277,6 @@ cloudflare_terraform_v5() - Renamed to `cloudflare_workers_for_platforms_dispatch_namespace` -## cloudflare_zone_dnssec - -- Renamed to `cloudflare_dns_zone_dnssec` - ## cloudflare_managed_headers - Renamed to `cloudflare_managed_transforms` @@ -830,6 +849,10 @@ resource "cloudflare_api_token" "example" { } ``` +## cloudflare_custom_page + +- `cloudflare_custom_page` has been removed. + ## cloudflare_zone_settings_override - `cloudflare_zone_settings_override` has been removed. Use `cloudflare_zone_setting` instead on a per setting basis. @@ -1118,6 +1141,9 @@ resource "cloudflare_api_token" "example" { ## cloudflare_dns_record - `data` is now a single nested attribute (`data = { ... }`) instead of a block (`data { ... }`). +- `data.flag` is now a number (`flag = 0`) instead of a string (`flag = "0"`). +- `hostname` has been removed. Instead, you should use a combination of data source and resource attributes to get the same value. +- `allow_overwrite` has been removed. ## cloudflare_zero_trust_risk_behavior @@ -1138,7 +1164,7 @@ resource "cloudflare_api_token" "example" { - `from_list` is now a list of objects (`from_list = [{ ... }]`) instead of multiple block attribute (`from_list { ... }`). - `from_value` is now a list of objects (`from_value = [{ ... }]`) instead of multiple block attribute (`from_value { ... }`). - `header` is now a list of objects (`header = [{ ... }]`) instead of multiple block attribute (`header { ... }`). -- `headers` is now a list of objects (`headers = [{ ... }]`) instead of multiple block attribute (`headers { ... }`). +- `headers` is now a map of attributes keyed by the name instead of multiple block attribute (`headers { ... }`). - `host` is now a list of objects (`host = [{ ... }]`) instead of multiple block attribute (`host { ... }`). - `logging` is now a single nested attribute (`logging = { ... }`) instead of a block (`logging { ... }`). - `matched_data` is now a list of objects (`matched_data = [{ ... }]`) instead of multiple block attribute (`matched_data { ... }`). @@ -1228,9 +1254,6 @@ resource "cloudflare_api_token" "example" { ## cloudflare_workers_script - `name` is now `script_name`. -- `compatibility_date` is now `metadata.compatibility_date`. -- `compatibility_flags` is now `metadata.compatibility_flags`. -- `tags` is now `metadata.tags`. - `analytics_engine_binding` is now a list of objects (`analytics_engine_binding = [{ ... }]`) instead of multiple block attribute (`analytics_engine_binding { ... }`). - `d1_database_binding` is now a list of objects (`d1_database_binding = [{ ... }]`) instead of multiple block attribute (`d1_database_binding { ... }`). - `kv_namespace_binding` is now a list of objects (`kv_namespace_binding = [{ ... }]`) instead of multiple block attribute (`kv_namespace_binding { ... }`). diff --git a/templates/resources/list.md.tmpl b/templates/resources/list.md.tmpl deleted file mode 100644 index 6535756926..0000000000 --- a/templates/resources/list.md.tmpl +++ /dev/null @@ -1,33 +0,0 @@ ---- -page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" -subcategory: "" -description: |- -{{ .Description | plainmarkdown | trimspace | prefixlines " " }} ---- - -# {{.Name}} ({{.Type}}) - -{{ .Description | trimspace }} - -~> The `cloudflare_list` resource supports defining list items in line with the - `item` attribute. The provider also has a `cloudflare_list_item` resource for - managing items as independent resources. Using both in line `item` definitions - _and_ `cloudflare_list_items` on the same list is not supported and will cause - Terraform into an irreconcilable state. - -{{ if .HasExample -}} -## Example Usage - -{{codefile "terraform" .ExampleFile}} -{{- end }} -{{ .SchemaMarkdown | trimspace }} - -{{ if .HasImport -}} -{{ if .HasImport -}} -## Import - -Import is supported using the following syntax: - -{{codefile "shell" .ImportFile}} -{{- end }} -{{- end }} diff --git a/templates/resources/magic_firewall_ruleset.md.tmpl b/templates/resources/magic_firewall_ruleset.md.tmpl deleted file mode 100644 index 7b2cf4510d..0000000000 --- a/templates/resources/magic_firewall_ruleset.md.tmpl +++ /dev/null @@ -1,59 +0,0 @@ ---- -layout: "cloudflare" -page_title: "Cloudflare: cloudflare_magic_firewall_ruleset" -description: Provides the ability to manage a Magic Firewall Ruleset and it's firewall rules which are used with Magic Transit. ---- - -# cloudflare_magic_firewall_ruleset - -Magic Firewall is a network-level firewall to protect networks that are onboarded to Cloudflare's Magic Transit. This resource -creates a root ruleset on the account level and contains one or more rules. Rules can be crafted in Wireshark syntax and -are evaluated in order, with the first rule having the highest priority. - -## Example Usage - -```hcl -resource "cloudflare_magic_firewall_ruleset" "example" { - account_id = "d41d8cd98f00b204e9800998ecf8427e" - name = "Magic Transit Ruleset" - description = "Global mitigations" - - rules = [ - { - action = "allow" - expression = "tcp.dstport in { 32768..65535 }" - description = "Allow TCP Ephemeral Ports" - enabled = "true" - }, - { - action = "block" - expression = "ip.len >= 0" - description = "Block all" - enabled = "true" - } - ] -} -``` - -## Argument Reference - -The following arguments are supported: - -- `account_id` - (Required) The ID of the account where the ruleset is being created. -- `name` - (Required) The name of the ruleset. -- `description` - (Optional) A note that can be used to annotate the ruleset. - -The **rules** block is a list of maps with the following attributes: - -- `action` - (Required) Valid values: `allow` or `block`. -- `expression` - (Required) A Firewall expression using Wireshark syntax. -- `description` - (Optional) A note that can be used to annotate the rule. -- `enabled` - (Required) Whether the rule is enabled or not. Valid values: `true` or `false`. - -## Import - -An existing Magic Firewall Ruleset can be imported using the account ID and ruleset ID - -``` -$ terraform import cloudflare_magic_firewall_ruleset.example d41d8cd98f00b204e9800998ecf8427e/cb029e245cfdd66dc8d2e570d5dd3322 -``` diff --git a/templates/resources/origin_ca_certificate.md.tmpl b/templates/resources/origin_ca_certificate.md.tmpl deleted file mode 100644 index 80192b3756..0000000000 --- a/templates/resources/origin_ca_certificate.md.tmpl +++ /dev/null @@ -1,29 +0,0 @@ ---- -page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" -subcategory: "" -description: |- -{{ .Description | plainmarkdown | trimspace | prefixlines " " }} ---- - -# {{.Name}} ({{.Type}}) - -{{ .Description | trimspace }} - -~> Since [v3.32.0](https://github.com/cloudflare/terraform-provider-cloudflare/releases/tag/v3.32.0) - all authentication schemes are supported for managing Origin CA certificates. - Versions prior to v3.32.0 will still need to use [`api_user_service_key`](../index.html#api_user_service_key). - -{{ if .HasExample -}} -## Example Usage - -{{codefile "terraform" .ExampleFile}} -{{- end }} -{{ .SchemaMarkdown | trimspace }} - -{{ if .HasImport -}} -## Import - -Import is supported using the following syntax: - -{{codefile "shell" .ImportFile}} -{{- end }} diff --git a/templates/resources/r2_bucket.md.tmpl b/templates/resources/r2_bucket.md.tmpl deleted file mode 100644 index 4e790505f9..0000000000 --- a/templates/resources/r2_bucket.md.tmpl +++ /dev/null @@ -1,24 +0,0 @@ ---- -page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}" -subcategory: "" -description: |- -{{ .Description | plainmarkdown | trimspace | prefixlines " " }} ---- - -# {{.Name}} ({{.Type}}) - -## Example Usage - -{{codefile "terraform" .ExampleFile}} - --> Available location values can be found in the [R2 documentation](https://developers.cloudflare.com/r2/reference/data-location/#available-hints). - -{{ .SchemaMarkdown | trimspace }} - -{{ if .HasImport -}} -## Import - -Import is supported using the following syntax: - -{{codefile "shell" .ImportFile}} -{{- end }} diff --git a/tools/acctestgen/main.go b/tools/acctestgen/main.go index 2ed7b2356e..57fe4f39d0 100644 --- a/tools/acctestgen/main.go +++ b/tools/acctestgen/main.go @@ -60,7 +60,7 @@ Example: go run cmd/acctest/main.go %s } input = strings.ToLower(input) if input != "y" && input != "yes" { - fmt.Println("\nFile creation aborted.\n") + fmt.Println("\nFile creation aborted") os.Exit(0) }