diff --git a/.ci/containers/downstream-builder/generate_downstream.sh b/.ci/containers/downstream-builder/generate_downstream.sh index 6f9c7503fe69..023058971686 100755 --- a/.ci/containers/downstream-builder/generate_downstream.sh +++ b/.ci/containers/downstream-builder/generate_downstream.sh @@ -4,7 +4,7 @@ set -e function clone_repo() { SCRATCH_OWNER=modular-magician - UPSTREAM_BRANCH=main + UPSTREAM_BRANCH=$BASE_BRANCH if [ "$REPO" == "terraform" ]; then if [ "$VERSION" == "ga" ]; then UPSTREAM_OWNER=hashicorp @@ -25,11 +25,12 @@ function clone_repo() { LOCAL_PATH=$GOPATH/src/github.com/GoogleCloudPlatform/terraform-google-conversion elif [ "$REPO" == "terraform-google-conversion" ]; then UPSTREAM_OWNER=GoogleCloudPlatform - UPSTREAM_BRANCH=main GH_REPO=terraform-google-conversion LOCAL_PATH=$GOPATH/src/github.com/GoogleCloudPlatform/terraform-google-conversion elif [ "$REPO" == "tf-oics" ]; then - UPSTREAM_BRANCH=master + if [ "$UPSTREAM_BRANCH" == "main" ]; then + UPSTREAM_BRANCH=master + fi UPSTREAM_OWNER=terraform-google-modules GH_REPO=docs-examples LOCAL_PATH=$GOPATH/src/github.com/terraform-google-modules/docs-examples @@ -45,7 +46,9 @@ function clone_repo() { GITHUB_PATH=https://modular-magician:$GITHUB_TOKEN@github.com/$UPSTREAM_OWNER/$GH_REPO SCRATCH_PATH=https://modular-magician:$GITHUB_TOKEN@github.com/$SCRATCH_OWNER/$GH_REPO mkdir -p "$(dirname $LOCAL_PATH)" - git clone $GITHUB_PATH $LOCAL_PATH + + echo "BASE_BRANCH: $BASE_BRANCH" + git clone $GITHUB_PATH $LOCAL_PATH --branch $UPSTREAM_BRANCH } if [ $# -lt 4 ]; then @@ -67,6 +70,12 @@ mkdir ../mm-$REPO-$VERSION-$COMMAND cp -rp ./. ../mm-$REPO-$VERSION-$COMMAND pushd ../mm-$REPO-$VERSION-$COMMAND +# for backwards-compatibility +if [ -z "$BASE_BRANCH" ]; then + BASE_BRANCH=main +fi + + clone_repo git config --local user.name "Modular Magician" @@ -112,20 +121,13 @@ if [ "$REPO" == "terraform-google-conversion" ]; then pushd $LOCAL_PATH - if [ "$VERSION" == "ga" ]; then - if [ "$COMMAND" == "downstream" ]; then - go get -d github.com/hashicorp/terraform-provider-google@main - else - go mod edit -replace github.com/hashicorp/terraform-provider-google=github.com/$SCRATCH_OWNER/terraform-provider-google@$BRANCH - fi - elif [ "$VERSION" == "beta" ]; then - if [ "$COMMAND" == "downstream" ]; then - go get -d github.com/hashicorp/terraform-provider-google-beta@main - else - go mod edit -replace github.com/hashicorp/terraform-provider-google-beta=github.com/$SCRATCH_OWNER/terraform-provider-google-beta@$BRANCH - fi + if [ "$COMMAND" == "downstream" ]; then + go get -d github.com/hashicorp/terraform-provider-google-beta@$BASE_BRANCH + else + go mod edit -replace github.com/hashicorp/terraform-provider-google-beta=github.com/$SCRATCH_OWNER/terraform-provider-google-beta@$BRANCH fi + go mod tidy # the following build can fail which results in a subsequent failure to push to tfv repository. @@ -155,6 +157,11 @@ else fi pushd ../ make tpgtools OUTPUT_PATH=$LOCAL_PATH VERSION=$VERSION + + # Only generate TeamCity-related file for TPG and TPGB + if [ "$VERSION" == "ga" ] || [ "$VERSION" == "beta" ]; then + make teamcity-servicemap-generate OUTPUT_PATH=$LOCAL_PATH VERSION=$VERSION + fi popd fi fi @@ -177,7 +184,7 @@ if [ "$REPO" == "terraform" ]; then fi PR_NUMBER=$(curl -L -s -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/pulls?state=closed&base=main&sort=updated&direction=desc" | \ + "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/pulls?state=closed&base=$BASE_BRANCH&sort=updated&direction=desc" | \ jq -r ".[] | if .merge_commit_sha == \"$REFERENCE\" then .number else empty end") if [ "$COMMITTED" == "true" ] && [ "$COMMAND" == "downstream" ] && [ "$CHANGELOG" == "true" ]; then # Add the changelog entry! @@ -222,4 +229,4 @@ if [ "$COMMITTED" == "true" ] && [ "$COMMAND" == "downstream" ]; then "https://api.github.com/repos/$UPSTREAM_OWNER/$GH_REPO/pulls/$NEW_PR_NUMBER/merge" fi -popd +popd \ No newline at end of file diff --git a/.ci/containers/downstream-waiter/wait_for_commit.sh b/.ci/containers/downstream-waiter/wait_for_commit.sh index 6d4fe13e55fc..b59bde2a3698 100755 --- a/.ci/containers/downstream-waiter/wait_for_commit.sh +++ b/.ci/containers/downstream-waiter/wait_for_commit.sh @@ -6,10 +6,18 @@ if [ $# -lt 3 ]; then exit 1 fi -SYNC_BRANCH=$1 +SYNC_BRANCH_PREFIX=$1 BASE_BRANCH=$2 SHA=$3 +if [ "$BASE_BRANCH" == "main" ]; then + SYNC_BRANCH=$SYNC_BRANCH_PREFIX +else + SYNC_BRANCH=$SYNC_BRANCH_PREFIX-$BASE_BRANCH +fi + +echo "SYNC_BRANCH: $SYNC_BRANCH" + if git merge-base --is-ancestor $SHA origin/$SYNC_BRANCH; then echo "Found $SHA in history of $SYNC_BRANCH - dying to avoid double-generating that commit." exit 1 @@ -25,4 +33,4 @@ while true; do git fetch origin $SYNC_BRANCH fi sleep 5 -done +done \ No newline at end of file diff --git a/.ci/containers/gcb-terraform-vcr-tester/test_terraform_vcr.sh b/.ci/containers/gcb-terraform-vcr-tester/test_terraform_vcr.sh index 58b5449d51df..0e0e5f0781da 100755 --- a/.ci/containers/gcb-terraform-vcr-tester/test_terraform_vcr.sh +++ b/.ci/containers/gcb-terraform-vcr-tester/test_terraform_vcr.sh @@ -54,11 +54,25 @@ function update_status { update_status "pending" +# for backwards-compatibility +if [ -z "$BASE_BRANCH" ]; then + BASE_BRANCH=main +else + echo "BASE_BRANCH: $BASE_BRANCH" +fi + set +e # cassette retrieval mkdir fixtures -gsutil -m -q cp gs://ci-vcr-cassettes/beta/fixtures/* fixtures/ -# copy branch specific cassettes over master. This might fail but that's ok if the folder doesnt exist +if [ "$BASE_BRANCH" != "FEATURE-BRANCH-major-release-5.0.0" ]; then + # pull main cassettes (major release uses branch specific casssettes as primary ones) + gsutil -m -q cp gs://ci-vcr-cassettes/beta/fixtures/* fixtures/ +fi +if [ "$BASE_BRANCH" != "main" ]; then + # copy feature branch specific cassettes over main. This might fail but that's ok if the folder doesnt exist + gsutil -m -q cp gs://ci-vcr-cassettes/beta/refs/branches/$BASE_BRANCH/fixtures/* fixtures/ +fi +# copy PR branch specific cassettes over main. This might fail but that's ok if the folder doesnt exist gsutil -m -q cp gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$pr_number/fixtures/* fixtures/ echo $SA_KEY > sa_key.json diff --git a/.ci/containers/membership-checker/REVIEWER_ASSIGNMENT_COMMENT.md b/.ci/containers/membership-checker/REVIEWER_ASSIGNMENT_COMMENT.md index d81909e79447..adad1a09a309 100644 --- a/.ci/containers/membership-checker/REVIEWER_ASSIGNMENT_COMMENT.md +++ b/.ci/containers/membership-checker/REVIEWER_ASSIGNMENT_COMMENT.md @@ -1,21 +1,3 @@ -Hello! I am a robot who works on Magic Modules PRs. +Hello! I am a robot. It looks like you are a community contributor. @{{reviewer}}, a repository maintainer, has been assigned to review your changes. If you have not received review feedback within 2 business days, please leave a comment on this PR asking them to take a look. -I've detected that you're a community contributor. @{{reviewer}}, a repository maintainer, has been assigned to assist you and help review your changes. - -
- :question: First time contributing? Click here for more details - ---- - -Your assigned reviewer will help review your code by: -* Ensuring it's backwards compatible, covers common error cases, etc. -* Summarizing the change into a user-facing changelog note. -* Passes tests, either our "VCR" suite, a set of presubmit tests, or with manual test runs. - -You can help make sure that review is quick by running local tests and ensuring they're passing in between each push you make to your PR's branch. Also, try to leave a comment with each push you make, as pushes generally don't generate emails. - -If your reviewer doesn't get back to you within a week after your most recent change, please feel free to leave a comment on the issue asking them to take a look! In the absence of a dedicated review dashboard most maintainers manage their pending reviews through email, and those will sometimes get lost in their inbox. - ---- - -
\ No newline at end of file +You can help make sure that review is quick by [doing a self-review](https://googlecloudplatform.github.io/magic-modules/contribute/review-pr/) and by [running impacted tests locally](https://googlecloudplatform.github.io/magic-modules/get-started/run-provider-tests/). \ No newline at end of file diff --git a/.ci/containers/vcr-cassette-merger/vcr_merge.sh b/.ci/containers/vcr-cassette-merger/vcr_merge.sh index daedc615d23f..93d7be0a77a3 100755 --- a/.ci/containers/vcr-cassette-merger/vcr_merge.sh +++ b/.ci/containers/vcr-cassette-merger/vcr_merge.sh @@ -4,15 +4,26 @@ set -e REFERENCE=$1 +# for backwards-compatibility +if [ -z "$BASE_BRANCH" ]; then + BASE_BRANCH=main +else + echo "BASE_BRANCH: $BASE_BRANCH" +fi + PR_NUMBER=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/pulls?state=closed&base=main&sort=updated&direction=desc" | \ + "https://api.github.com/repos/GoogleCloudPlatform/magic-modules/pulls?state=closed&base=$BASE_BRANCH&sort=updated&direction=desc" | \ jq -r ".[] | if .merge_commit_sha == \"$REFERENCE\" then .number else empty end") set +e gsutil ls gs://ci-vcr-cassettes/refs/heads/auto-pr-$PR_NUMBER/fixtures/ if [ $? -eq 0 ]; then # We have recorded new cassettes for this branch - gsutil -m cp gs://ci-vcr-cassettes/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/fixtures/ + if [ "$BASE_BRANCH" == "main" ]; then + gsutil -m cp gs://ci-vcr-cassettes/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/fixtures/ + else + gsutil -m cp gs://ci-vcr-cassettes/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/refs/branches/$BASE_BRANCH/fixtures/ + fi gsutil -m rm -r gs://ci-vcr-cassettes/refs/heads/auto-pr-$PR_NUMBER/ fi @@ -20,9 +31,13 @@ fi gsutil ls gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$PR_NUMBER/fixtures/ if [ $? -eq 0 ]; then # We have recorded new cassettes for this branch - gsutil -m cp gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/beta/fixtures/ + if [ "$BASE_BRANCH" == "main" ]; then + gsutil -m cp gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/beta/fixtures/ + else + gsutil -m cp gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$PR_NUMBER/fixtures/* gs://ci-vcr-cassettes/beta/refs/branches/$BASE_BRANCH/fixtures/ + fi gsutil -m rm -r gs://ci-vcr-cassettes/beta/refs/heads/auto-pr-$PR_NUMBER/ fi -set -e +set -e \ No newline at end of file diff --git a/.ci/gcb-generate-diffs-new.yml b/.ci/gcb-generate-diffs-new.yml index 571ba04a045f..b684c5e0a67c 100644 --- a/.ci/gcb-generate-diffs-new.yml +++ b/.ci/gcb-generate-diffs-new.yml @@ -76,6 +76,8 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tpg-head waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'head' - 'terraform' @@ -86,6 +88,8 @@ steps: id: tpg-base secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'base' - 'terraform' @@ -96,6 +100,8 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tpgb-head waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'head' - 'terraform' @@ -106,6 +112,8 @@ steps: id: tpgb-base secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'base' - 'terraform' @@ -116,25 +124,31 @@ steps: id: tgc-head secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged", "tpg-head"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'head' - 'terraform-google-conversion' - - 'ga' + - 'beta' - $_PR_NUMBER - name: 'gcr.io/graphite-docker-images/downstream-builder' id: tgc-base secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged", "tpg-base"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'base' - 'terraform-google-conversion' - - 'ga' + - 'beta' - $_PR_NUMBER - name: 'gcr.io/graphite-docker-images/downstream-builder' secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'head' - 'tf-oics' @@ -144,6 +158,8 @@ steps: - name: 'gcr.io/graphite-docker-images/downstream-builder' secretEnv: ["GITHUB_TOKEN"] waitFor: ["merged"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - 'base' - 'tf-oics' @@ -256,6 +272,8 @@ steps: id: gcb-tpg-vcr-test secretEnv: ["GITHUB_TOKEN", "GOOGLE_BILLING_ACCOUNT", "GOOGLE_CUST_ID", "GOOGLE_FIRESTORE_PROJECT", "GOOGLE_IDENTITY_USER", "GOOGLE_MASTER_BILLING_ACCOUNT", "GOOGLE_ORG", "GOOGLE_ORG_2", "GOOGLE_ORG_DOMAIN", "GOOGLE_PROJECT", "GOOGLE_PROJECT_NUMBER", "GOOGLE_SERVICE_ACCOUNT", "SA_KEY", "GOOGLE_PUBLIC_AVERTISED_PREFIX_DESCRIPTION"] waitFor: ["diff"] + env: + - BASE_BRANCH=$_BASE_BRANCH args: - $_PR_NUMBER - $COMMIT_SHA diff --git a/.ci/gcb-push-downstream.yml b/.ci/gcb-push-downstream.yml index 2513a8beabd8..83a9849b095f 100644 --- a/.ci/gcb-push-downstream.yml +++ b/.ci/gcb-push-downstream.yml @@ -38,6 +38,8 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tpg-push waitFor: ["tpg-sync"] + env: + - BASE_BRANCH=$BRANCH_NAME args: - 'downstream' - 'terraform' @@ -50,7 +52,12 @@ steps: entrypoint: 'bash' args: - -c - - git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpg-sync + - | + if [ "$BRANCH_NAME" == "main" ]; then + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpg-sync + else + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpg-sync-$BRANCH_NAME + fi # TPGB - name: 'gcr.io/graphite-docker-images/downstream-waiter' @@ -66,6 +73,8 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tpgb-push waitFor: ["tpgb-sync"] + env: + - BASE_BRANCH=$BRANCH_NAME args: - 'downstream' - 'terraform' @@ -78,7 +87,12 @@ steps: entrypoint: 'bash' args: - -c - - git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpgb-sync + - | + if [ "$BRANCH_NAME" == "main" ]; then + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpgb-sync + else + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tpgb-sync-$BRANCH_NAME + fi # TGC - name: 'gcr.io/graphite-docker-images/downstream-waiter' @@ -94,10 +108,12 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tgc-push waitFor: ["tgc-sync", "tpg-push"] + env: + - BASE_BRANCH=$BRANCH_NAME args: - 'downstream' - 'terraform-google-conversion' - - 'ga' + - 'beta' - $COMMIT_SHA - name: 'gcr.io/cloud-builders/git' @@ -106,7 +122,12 @@ steps: entrypoint: 'bash' args: - -c - - git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tgc-sync + - | + if [ "$BRANCH_NAME" == "main" ]; then + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tgc-sync + else + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tgc-sync-$BRANCH_NAME + fi # TF-OICS - name: 'gcr.io/graphite-docker-images/downstream-waiter' @@ -122,6 +143,8 @@ steps: secretEnv: ["GITHUB_TOKEN"] id: tf-oics-push waitFor: ["tf-oics-sync"] + env: + - BASE_BRANCH=$BRANCH_NAME args: - 'downstream' - 'tf-oics' @@ -134,11 +157,18 @@ steps: entrypoint: 'bash' args: - -c - - git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tf-oics-sync + - | + if [ "$BRANCH_NAME" == "main" ]; then + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tf-oics-sync + else + git push https://modular-magician:$$GITHUB_TOKEN@github.com/GoogleCloudPlatform/magic-modules $COMMIT_SHA:tf-oics-sync-$BRANCH_NAME + fi - name: 'gcr.io/graphite-docker-images/vcr-cassette-merger' secretEnv: ["GITHUB_TOKEN", "GOOGLE_PROJECT"] waitFor: ["tpg-push"] + env: + - BASE_BRANCH=$BRANCH_NAME args: - $COMMIT_SHA diff --git a/GNUmakefile b/GNUmakefile index aa68253ad701..58f255cb87bc 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -59,6 +59,7 @@ terraform build provider: @make validate_environment; make mmv1 make tpgtools + make teamcity-servicemap-generate mmv1: cd mmv1;\ @@ -70,10 +71,16 @@ tpgtools: cd tpgtools;\ go run . --output $(OUTPUT_PATH) --version $(VERSION) $(tpgtools_compile) +# This should be removed when all DCL resources are migrated to MMv1; service map generation should be +# controlled inside MMv1, like originally implemented in this PR: https://github.com/GoogleCloudPlatform/magic-modules/pull/8254 +teamcity-servicemap-generate: + cd tools/teamcity-generator;\ + go run . --output $(OUTPUT_PATH) --version $(VERSION) + tgc: cd mmv1;\ bundle;\ - bundle exec compiler -e terraform -f validator -o $(OUTPUT_PATH) $(mmv1_compile);\ + bundle exec compiler -e terraform -f validator -v beta -o $(OUTPUT_PATH) $(mmv1_compile);\ test: cd mmv1; \ diff --git a/docs/content/contribute/review-pr.md b/docs/content/contribute/review-pr.md index 01e3b67f40cd..7a8dfe6506db 100644 --- a/docs/content/contribute/review-pr.md +++ b/docs/content/contribute/review-pr.md @@ -17,12 +17,13 @@ This page provides guidelines for reviewing Magic Modules pull requests 1. the features are added in the correct version * features only available in beta are not included in the GA google provider. * features added to the GA provider are also included in the beta provider -- beta should be a strict superset of GA. - 1. no [breaking changes]({{< ref "/develop/breaking-changes" >}}) are introduced without a valid justification. + 1. no [breaking changes]({{< ref "/develop/make-a-breaking-change" >}}) are introduced without a valid justification. 1. verify the change actually resolves the linked issues, if any. 1. Check the tests added/modified to ensure that: 1. all fields added/updated in the PR appear in at least one test. * It is advisable to test updating from a non-zero value to a zero value if feasible. 1. all mutable fields are tested in at least one update test. + 1. all resources in the acceptance tests have a `tf-test` or `tf_test` prefix in their primary id field. 1. all related tests pass in GA for features promoted from beta to GA. {{< hint info >}}Note: Presubmit VCR tests do not run in GA. Manual testing is required for promoted GA features. @@ -42,4 +43,4 @@ This page provides guidelines for reviewing Magic Modules pull requests 1. Check documentation to ensure 1. resouce-level and field-level documentation are generated correctly for MMv1-based resource 1. documentation is added manually for handwritten resources. -1. Check if release notes capture all changes in the PR, and are correctly formatted following the guidance in [write release notes]({{< ref "release-notes" >}}) before merge the PR. \ No newline at end of file +1. Check if release notes capture all changes in the PR, and are correctly formatted following the guidance in [write release notes]({{< ref "release-notes" >}}) before merge the PR. diff --git a/docs/content/develop/breaking-changes.md b/docs/content/develop/breaking-changes.md deleted file mode 100644 index f0192a635f9f..000000000000 --- a/docs/content/develop/breaking-changes.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "Understand breaking changes" -summary: "This page discusses provider versioning, handling of breaking changes, and rare exceptions within Terraform development." -weight: 12 ---- - - -# Breaking Changes and Provider Development - -## Provider Versioning -As a provider is developed, resources are added, old resources are updated, and bugs are fixed. These changes are [bundled together as a release](https://github.com/hashicorp/terraform-provider-google/releases/tag/v4.32.0). - -Releases are numerically defined with a version number in the form of `MAJOR.MINOR.PATCH`. Here, 'Patch' indicates bug fixes, 'Minor' represents new features, and 'Major' represents significant changes which would be breaking to the customer if committed. Once a release is published, the provider binary is copied to [Hashicorp's provider registry](https://registry.terraform.io/browse/providers). - -## Customer Trust -Terraform authors can write modular configurations, aptly named modules. These are shared within organizations and [online](https://registry.terraform.io/browse/modules). Terraform configurations can specify [provider requirements](https://www.terraform.io/language/providers/requirements), including a [version constraint field](https://www.terraform.io/language/providers/requirements#version-constraints). - -The configuration will then [tie these version constraints](https://www.terraform.io/language/expressions/version-constraints) to an approximate minor or exact full version. Maintaining trust and consistency on every `MINOR` or `MAJOR` version upgrade is critical. - -If breaking changes are allowed within `MINOR` versions, trust in the provider will be eroded and module creators will not have confidence in provider stability. This diminished trust will eventually lead to customers investing or deploying less to GCP. - -## Exceptions to Breaking Changes - -While we strive to minimize breaking changes, there are certain exceptions where they become unavoidable. Notably, breaking changes are permissible when existing functionality is demonstrably broken due to an API or provider-level issue. In such cases, the change does not impact users negatively, since there is no instance where the Terraform provider is currently using the affected field or resource correctly. - -For example, consider a situation involving the Google provider where an API endpoint we depend on changes its behavior or is deprecated. If the current implementation in the Terraform provider cannot adapt to this change and is thus broken, a breaking change would be necessary to restore the functionality. - -## Breaking Changes - -Having established that we want to avoid breaking changes, let's delve into what exactly constitutes a breaking change. We'll discuss this under four main categories and the rules within each. - -### Provider Configuration Level Breakages - -* Top-level behavior such as provider configuration and authentication changes. - -

Changing fundamental provider behavior (Undetectable)

- -Including, but not limited to, modification of: authentication, environment variable usage, and constricting retry behavior. - -### Resource List Level Breakages - -* Resource/datasource naming conventions and entry differences. - -

Removing or Renaming a Resource

- -In Terraform, resources should be retained whenever possible. Removal of a resource will result in a configuration breakage wherever a dependency on that resource exists. Renaming or removing resources are functionally equivalent in terms of configuration breakages. - -### Resource Level Breakages - -* Individual resource breakages like field entry removals or behavior within a resource. - -

Removing or Renaming a field

- -In Terraform, fields should be retained whenever possible. Removal of a field will result in a configuration breakage wherever a dependency on that field exists. Renaming or removing a field are functionally equivalent in terms of configuration breakages. - -

Changing resource ID format (Undetectable)

- -Terraform uses resource ID to read resource state from the API. Modification of the ID format will break the ability to parse the IDs from any deployments. - -

Changing resource ID import format (Undetectable)

- -Automation external to our provider may rely on importing resources with a certain format. Removal or modification of existing formats will break this automation. - -### Field Level Breakages - -* Field-level conventions like attribute changes and naming conventions. - -

Changing Field Type

- -While certain Field Type migrations may be supported at a technical level, it's a practice that we highly discourage. We see little value for these transitions vs the risk they impose. - -

Field becoming Required Field

- -A field should not become 'Required' as existing configurations may not have this field defined, leading to broken configurations in sequential plans or applies.. If you are adding 'Required' to a field so a block won't remain empty, this can cause two issues. First, if it's a singular nested field, the block may gain more fields later and it's not clear whether the field is actually required so it may be misinterpreted by future contributors. Second, if users are defining empty blocks in existing configurations, this change will break them. Consider these points in admittance of this type of change. - -

Becoming a Computed only Field

- -While a field can transition from 'Optional' to 'Optional+Computed', it should not change from 'Required' or 'Optional' to solely 'Computed'. This transition would effectively make the field read-only, thus breaking configs in sequential plan or applies where this field is defined in a configuration. - -

Optional and Computed to Optional

- -A field should not transition from 'Computed + Optional' to 'Optional'. During a sequential apply, the Terraform state retains the previously computed value, which won't match the configuration, thus causing a discrepancy. - -

Adding or Changing a Default Value

- -Adding a default value where one was not previously declared can work in a very limited subset of scenarios but is an all around 'not good' practice to engage in. Changing a default value will absolutely cause a breakage. The mechanism of break for both scenarios is current terraform deployments now gain a diff with sequential applies where the diff is the new or changed default value. - -

Growing Minimum Items

- -'MinItems' cannot grow. Otherwise, existing terraform configurations that don't satisfy this rule will break. - -

Shrinking Maximum Items

- -'MaxItems' cannot shrink. Otherwise, existing terraform configurations that don't satisfy this rule will break. - -

Changing field data format (Undetectable)

- -Modification of the data format (either by the API or manually) will cause a diff in subsequent plans if that field is not Computed. This results in a breakage. API breaking changes are out of scope with respect to provider responsibility but we may make changes in response to API breakages in some instances to provide more customer stability. - diff --git a/docs/content/develop/make-a-breaking-change.md b/docs/content/develop/make-a-breaking-change.md new file mode 100644 index 000000000000..0edfd032a2de --- /dev/null +++ b/docs/content/develop/make-a-breaking-change.md @@ -0,0 +1,208 @@ +--- +title: "Make a breaking change" +summary: "Guidance on making a breaking change during a major release" +weight: 95 +--- + +# How to make a breaking change + +{{< hint info >}} +**Note:** This page covers the general requirements to make a breaking change +and may not include exact, comprehensive details on making your change. Breaking +changes are generally complicated and resource or field specific traits can +drastically change how they need to be made. +{{< /hint >}} + +## When to (or not to) make a breaking change + +Within the Terraform ecosystem, there's a strong expectation of stability +**including across major versions**. Ecosystem-wide, the community has had +deeply negative reactions to provider changes with overly-broad impact, and +too-large changes can delay customers upgrading to adopt new major versions. + +In general, we recommend avoiding breaking changes where possible. The +provider's schema is an API surface relied on by many GCP customers, and users +have responded negatively to instability in our surface and those of other +providers. + +While the cost to make a change in the provider is relatively cheap, it has +knock-on effects through the whole ecosystem: + +* Modules need to update to adapt to the breaking changes +* Customers need to update their provider version (and module versions) +* Terraform assistive tools like [`gcloud terraform vet`](https://cloud.google.com/docs/terraform/policy-validation/quickstart) + and 3P tools with provider dependencies like + [Config Connector](https://cloud.google.com/config-connector/docs/overview) + and [Pulumi GCP Classic](https://www.pulumi.com/registry/packages/gcp/) need + to be updated + +When breaking changes are made, they must be made within a major release +(typically yearly) and meet the stringent ecosystem requirements for a breaking +change, detailed below. + +## What counts as a breaking change? + +While the general versioning model for providers is captured +in https://developer.hashicorp.com/terraform/plugin/best-practices/versioning, +that documentation serves as a baseline for new provider development and not +guidelines for mature providers like the major cloud providers. + +The standard our joint Google & HashiCorp team has developed is that any change +that requires an end user to modify any previously-valid configuration after a +provider upgrade is a breaking change, and must happen in a major release. In +this context "valid" means that a configuration is syntactically correct +(passes `terraform validate`) and runs in `terraform apply` without returning an +error. This means that minor corrections are possible such as marking immutable +fields as immutable if they previously weren't. + +There is a single exception to this rule- if a user has managed a resource +out-of-band from Terraform to enable a new field with a non-default value, +adding support for the field without handling that case is permissible. +Terraform will generate a plan that reconciles their state with their live +configuration. + +For example, the following are (a non-exhaustive list of) breaking changes: + +* Changing the output format of a field (i.e. from an integer to a string, or + the pattern of a structured value) +* Adding a new required field or changing an existing non-required field to + required +* Removing a field +* Major behaviour changes to a resource (if configurable, if they are done by + default) + +Meanwhile, the following are allowed in a minor version: + +* Adding a new field +* Adding update support for a field +* Removing update support from a field that returned an error in **all cases** a + user attempted to update it +* Marking a field required if *all configurations** that did not specify the + field returned an error +* Major behavioural changes guarded by a flag where the **previous** behaviour + is the default + +## Making a breaking change + +{{< hint info >}} +**Note:** This section of the document refers to several release versions of the +provider at once. Breaking changes are made in major releases such as 1.0.0, +4.0.0, or 4.0.0 (referred to as the "major release" or `N` here) while typical +provider releases are minor versions, most notably the last minor release of the +previous major release series such as `2.20.3` for `3.0.0` or `3.90.1` +for `4.0.0` (referred to as the "last minor release" or `N-1.X` here). +{{}} + +The Terraform provider ecosystem follows the standard that deprecations or +warnings must be resolvable by end users in the last minor release of the prior +release series before their removal or change in a major release. Additionally, +deprecation warnings must be actionable- at the time a deprecation is posted, a +user must be able to remove the field. + +### Contributing to the next major release (`5.0.0`) + +For the `5.0.0` major release, the major release branch that you'll contribute to is [`FEATURE-BRANCH-major-release-5.0.0`](https://github.com/GoogleCloudPlatform/magic-modules/tree/FEATURE-BRANCH-major-release-5.0.0). +All breaking changes targeting `5.0.0` must be committed to this branch. + +A downstream branch with the same name `FEATURE-BRANCH-major-release-5.0.0` will be used to track the generated `5.0.0` changes in both [`google`](https://github.com/hashicorp/terraform-provider-google/tree/FEATURE-BRANCH-major-release-5.0.0) and [`google-beta`](https://github.com/hashicorp/terraform-provider-google-beta/tree/FEATURE-BRANCH-major-release-5.0.0) provider repos. + +The process of contributing to the major release `5.0.0` follows most of the [General contributing steps]({{< ref "/get-started/contributing" >}}), with the following exceptions + +1. Use `FEATURE-BRANCH-major-release-5.0.0` branch instead of the `main` branch as the base branch when you + * checkout your working branch where you make your code changes. + * sync your working branch using `git rebase` or `git merge`. + * create a pull request in the magic-modules repo. +2. Make sure that you checkout to the `FEATURE-BRANCH-major-release-5.0.0` branch in your downstream `google` and `google-beta` repos before generating the providers locally. +3. If your change is a follow-up to a recent commit to main that is not yet contained in the released branch, it is strongly encouraged to wait until the branch sync and resolve any merge conflicts in the PR. + For example, if you are removing a field that has been recently deprecated in main. + +The release branch is synced with main on a weekly basis every Monday. + + +### Renaming a field + +The most common type of breaking change is a field rename, and most guidance is +tuned around that. To perform one, a provider contributor must: + +1. Add support for the new field on or before the last minor release of the + preceding release series (i.e. version `N-1.X.0`) by contributing to + the `main` branch in the magic-modules repo +2. Mark the old field deprecated on or before the last minor release of the + preceding release series (i.e. version `N-1.X.0`) by contributing to + the `main` branch in the magic-modules repo +3. Write an upgrade guide entry in the major release's upgrade guide (such + as [this one](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_5_upgrade) + for `5.0.0`) by contributing to the `main` branch in the magic-modules repo +4. Remove the old field from the major release (i.e. version `N`) in the major + release branch in the magic-modules repo + +For example, if `google_foobar` has a field `baz` in version `3.80.0` that is +being replaced by `qux` in `4.0.0`, `qux` must be added on or before `3.90.1`, +and `baz` must be deprecated within the same window (either at the same time +as `qux` is added, or afterwards (if added earlier than `3.90.1`), but not +before). + +Example (`google_storage_bucket.bucket_policy_only` -> `google_storage_bucket.uniform_bucket_level_access`) +* https://github.com/GoogleCloudPlatform/magic-modules/pull/3916 introduced the new field and deprecated the original one in `3.38.0` +* https://github.com/GoogleCloudPlatform/magic-modules/pull/5340 added the upgrade guide entry and removed the field in `4.0.0` +* Note: In 4.0.0 the upgrade guide was split between main and the major release branch. Going forward, those changes will be made against main exclusively. + +### Removing a field + +Removing a field is similar to renaming one, except that a new field doesn't +need to be introduced: + +1. Mark the field deprecated on or before the last minor release of the + preceding release series (i.e. version `N-1.X.0`) by contributing to + the `main` branch in the magic-modules repo +2. Write an upgrade guide entry in the major release's upgrade guide (such + as [this one](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_5_upgrade) + for `5.0.0`) by contributing to the `main` branch in the magic-modules repo +3. Remove the field from the major release (i.e. version `N`) in the major + release branch in the magic-modules repo + +Example (`google_container_cluster.instance_group_urls`) +* https://github.com/GoogleCloudPlatform/magic-modules/pull/5261 deprecated `instance_group_urls` and filled out the upgrade guide +* https://github.com/GoogleCloudPlatform/magic-modules/pull/5378 removed the field + +### Marking optional fields required + +There is no way to message a change to users in advance at the moment, other +than through the upgrade guide. + +1. Write an upgrade guide entry in the major release's upgrade guide (such + as [this one](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_5_upgrade) + for `5.0.0`) by contributing to the `main` branch in the magic-modules repo +2. Mark the field as required in the major release (i.e. version `N`) in the major + release branch in the magic-modules repo + +Example (`google_app_engine_standard_app_version.entrypoint`) +* https://github.com/GoogleCloudPlatform/magic-modules/pull/5318 marked the field required and added an upgrade guide entry +* Note: In 4.0.0 the upgrade guide was split between main and the major release branch. Going forward, those changes will be made against main exclusively. + +### Changing default values + +Default values in Terraform are used to replace null values in configuration at +plan/apply time and **do not** respect previously-configured values by the user. +These changes are often undesirable, as their impact is extremely broad. + +When a default is changed, every user that has not specified an explicit value in their configuration will see Terraform propose changing the value of the field **including** if the change will destroy and recreate the resource due to changing an immutable value. Default changes in the provider are comparable in impact to default changes in an API, and modifying examples and modules may achieve the intended effect with a smaller blast radius. + +There is no way to message a change to users in advance at the moment, other +than through the upgrade guide. + +1. Write an upgrade guide entry in the major release's upgrade guide (such + as [this one](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/version_5_upgrade) + for `5.0.0`) by contributing to the `main` branch in the magic-modules repo +2. Mark the new default in the major release (i.e. version `N`) in the major + release branch in the magic-modules repo + +Example (`google_container_cluster.enable_shielded_nodes`) +* https://github.com/GoogleCloudPlatform/magic-modules/pull/5263 changed the default value for the field and added an upgrade guide entry +* Note: In 4.0.0 the upgrade guide was split between main and the major release branch. Going forward, those changes will be made against main exclusively. + +## References + +* Terraform (Provider) Plugin Development + * [Versioning and Changelog](https://developer.hashicorp.com/terraform/plugin/best-practices/versioning) + * [SDKv2 Deprecations, Removals, and Renames](https://developer.hashicorp.com/terraform/plugin/sdkv2/best-practices/deprecations) diff --git a/docs/content/develop/resource.md b/docs/content/develop/resource.md index 139984613015..2a3aad1c6f03 100644 --- a/docs/content/develop/resource.md +++ b/docs/content/develop/resource.md @@ -145,21 +145,14 @@ For more information about types of resources and the generation process overall # actions: ['create', 'update', 'delete'] operation: !ruby/object:Api::OpAsync::Operation base_url: '{{op_id}}' - # If true, the completed operation's returned JSON is expected to - # contain a full resource in the "response" field + + # If true, the provider sets the resource's Terraform ID after the resource is created, + # taking into account values that are set by the API at create time. This is only possible + # when the completed operation's JSON includes the created resource in the "response" field. + # If false (or unset), the provider sets the resource's Terraform ID before the resource is + # created, based only on the resource configuration. # result: !ruby/object:Api::OpAsync::Result # resource_inside_response: true - # The following are all required but unused. - path: 'unused' - wait_ms: 0 # unused - result: !ruby/object:Api::OpAsync::Result - path: 'unused' - status: !ruby/object:Api::OpAsync::Status - path: 'unused' - allowed: [] - error: !ruby/object:Api::OpAsync::Error - path: 'unused' - message: 'unused' # All resources (of all kinds) that share a mutex value block rather than # executing concurrent API requests. @@ -379,8 +372,9 @@ iam_policy: !ruby/object:Api::Resource::IamPolicy # Allowed values: :POST, :PUT. Default: :POST # set_iam_policy_verb: :POST - # Must match the parent resource's import_format, but with the - # parent_resource_attribute value substituted for the final field. + # Must match the parent resource's `import_format` (or `self_link` if + # `import_format` is unset), but with the `parent_resource_attribute` + # value substituted for the final field. import_format: [ 'projects/{{project}}/locations/{{location}}/resourcenames/{{resource_name}}' ] @@ -405,7 +399,14 @@ iam_policy: !ruby/object:Api::Resource::IamPolicy ### Add support in MMv1 -1. Follow the MMv1 directions in [Add the resource]({{}}) to create a skeleton ResourceName.yaml file for the handwritten resource, but set only the following top-level fields: `name`, `base_url` (set to URL of IAM parent resource), `self_link` (set to same value as `base_url`) `description` (required but unused), `id_format`, `import_format`, and `properties`. +1. Follow the MMv1 directions in [Add the resource]({{}}) to create a skeleton ResourceName.yaml file for the handwritten resource, but set only the following top-level fields: + - `name` + - `description` (required but unused) + - `base_url` (set to URL of IAM parent resource) + - `self_link` (set to same value as `base_url`) + - `id_format` (set to same value as `base_url`) + - `import_format` (including `base_url` value) + - `properties` 2. Follow the MMv1 directions in [Add fields]({{}}) to add only the fields used by base_url. 3. Follow the MMv1 directions in this section to add IAM support. diff --git a/docs/content/reference/breaking-change-detector.md b/docs/content/reference/breaking-change-detector.md new file mode 100644 index 000000000000..e508dfa9e606 --- /dev/null +++ b/docs/content/reference/breaking-change-detector.md @@ -0,0 +1,140 @@ +--- +title: "Breaking change detector" +summary: "This page discusses the breaking change detector analysis" +weight: 45 +aliases: +- /docs/content/develop/breaking-changes + +--- + +# Breaking change detector + +This page documents +the [breaking change detector](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/tools/breaking-change-detector) +analysis ran against PRs in this repo. + +The breaking change detector is a linter that is able to detect schema-level +breaking changes that have been proposed in a PR, and will flag them for your +reviewer. The rules are detailed below. Note that these are not exhaustive, and +reviewers may determine that a change is a breaking change based on more complex +criteria than the linter is capable of, such as runtime behaviors or other +rules. + +This page covers the analyses of the detector and is used to provide context for +contributors. If you're making a breaking change, +see [make a breaking change](/magic-modules/docs/develop/make-a-breaking-change) +for details on making a breaking change during a major release development +period. + +## Overriding the detector + +By default, the detector blocks merging PRs where a breaking change is detected. +If overriding it is required in order to bypass an incorrect rule, revert a bad +change, change an unreleased feature, etc., they can override it by applying +the `override-breaking-change` label to the PR. + +## Types of breakages + +### Provider Configuration Level Breakages + +* Top-level behavior such as provider configuration and authentication changes. + +

Changing fundamental provider behavior (Undetectable)

+ +Including, but not limited to, modification of: authentication, environment +variable usage, and constricting retry behavior. + +### Resource List Level Breakages + +* Resource/datasource naming conventions and entry differences. + +

Removing or Renaming a Resource

+ +In Terraform, resources should be retained whenever possible. Removal of a +resource will result in a configuration breakage wherever a dependency on that +resource exists. Renaming or removing resources are functionally equivalent in +terms of configuration breakages. + +### Resource Level Breakages + +* Individual resource breakages like field entry removals or behavior within a + resource. + +

Removing or Renaming a field

+ +In Terraform, fields should be retained whenever possible. Removal of a field +will result in a configuration breakage wherever a dependency on that field +exists. Renaming or removing a field are functionally equivalent in terms of +configuration breakages. + +

Changing resource ID format (Undetectable)

+ +Terraform uses resource ID to read resource state from the API. Modification of +the ID format will break the ability to parse the IDs from any deployments. + +

Changing resource ID import format (Undetectable)

+ +Automation external to our provider may rely on importing resources with a +certain format. Removal or modification of existing formats will break this +automation. + +### Field Level Breakages + +* Field-level conventions like attribute changes and naming conventions. + +

Changing Field Type

+ +While certain Field Type migrations may be supported at a technical level, it's +a practice that we highly discourage. We see little value for these transitions +vs the risk they impose. + +

Field becoming Required Field

+ +A field should not become 'Required' as existing configurations may not have +this field defined, leading to broken configurations in sequential plans or +applies.. If you are adding 'Required' to a field so a block won't remain empty, +this can cause two issues. First, if it's a singular nested field, the block may +gain more fields later and it's not clear whether the field is actually required +so it may be misinterpreted by future contributors. Second, if users are +defining empty blocks in existing configurations, this change will break them. +Consider these points in admittance of this type of change. + +

Becoming a Computed only Field

+ +While a field can transition from 'Optional' to 'Optional+Computed', it should +not change from 'Required' or 'Optional' to solely 'Computed'. This transition +would effectively make the field read-only, thus breaking configs in sequential +plan or applies where this field is defined in a configuration. + +

Optional and Computed to Optional

+ +A field should not transition from 'Computed + Optional' to 'Optional'. During a +sequential apply, the Terraform state retains the previously computed value, +which won't match the configuration, thus causing a discrepancy. + +

Adding or Changing a Default Value

+ +Adding a default value where one was not previously declared can work in a very +limited subset of scenarios but is an all around 'not good' practice to engage +in. Changing a default value will absolutely cause a breakage. The mechanism of +break for both scenarios is current terraform deployments now gain a diff with +sequential applies where the diff is the new or changed default value. + +

Growing Minimum Items

+ +'MinItems' cannot grow. Otherwise, existing terraform configurations that don't +satisfy this rule will break. + +

Shrinking Maximum Items

+ +'MaxItems' cannot shrink. Otherwise, existing terraform configurations that +don't satisfy this rule will break. + +

Changing field data format (Undetectable)

+ +Modification of the data format (either by the API or manually) will cause a +diff in subsequent plans if that field is not Computed. This results in a +breakage. API breaking changes are out of scope with respect to provider +responsibility but we may make changes in response to API breakages in some +instances to provide more customer stability. + diff --git a/mmv1/Gemfile b/mmv1/Gemfile index 55ac2b25e795..d53fb96dbf53 100644 --- a/mmv1/Gemfile +++ b/mmv1/Gemfile @@ -2,6 +2,7 @@ source 'https://rubygems.org' gem 'activesupport' gem 'binding_of_caller' +gem 'parallel' gem 'rake' group :test do diff --git a/mmv1/Gemfile.lock b/mmv1/Gemfile.lock index 97fbe1a48254..543109e879ea 100644 --- a/mmv1/Gemfile.lock +++ b/mmv1/Gemfile.lock @@ -63,6 +63,7 @@ DEPENDENCIES activesupport binding_of_caller mocha (~> 1.3.0) + parallel rake rspec rubocop (>= 0.77.0) diff --git a/mmv1/api/async.rb b/mmv1/api/async.rb index 14fc854bf2c4..f9cd84f00235 100644 --- a/mmv1/api/async.rb +++ b/mmv1/api/async.rb @@ -77,9 +77,9 @@ def validate super check :operation, type: Operation, required: true - check :result, type: Result, required: true - check :status, type: Status, required: true - check :error, type: Error, required: true + check :result, type: Result, default: Result.new + check :status, type: Status + check :error, type: Error check :actions, default: %w[create delete update], type: ::Array, item_type: ::String check :include_project, type: :boolean, default: false end @@ -100,9 +100,9 @@ def validate super check :kind, type: String - check :path, type: String, required: true + check :path, type: String check :base_url, type: String - check :wait_ms, type: Integer, required: true + check :wait_ms, type: Integer check :full_url, type: String @@ -130,8 +130,8 @@ class Status < Api::Object def validate super - check :path, type: String, required: true - check :allowed, type: Array, item_type: [::String, :boolean], required: true + check :path, type: String + check :allowed, type: Array, item_type: [::String, :boolean] end end @@ -142,8 +142,8 @@ class Error < Api::Object def validate super - check :path, type: String, required: true - check :message, type: String, required: true + check :path, type: String + check :message, type: String end end end diff --git a/mmv1/compiler.rb b/mmv1/compiler.rb index 9dad279216b5..aefeab2fd091 100755 --- a/mmv1/compiler.rb +++ b/mmv1/compiler.rb @@ -25,6 +25,7 @@ require 'api/compiler' require 'google/logger' require 'optparse' +require 'parallel' require 'pathname' require 'provider/terraform' require 'provider/terraform_kcc' @@ -127,12 +128,14 @@ allowed_classes = Google::YamlValidator.allowed_classes +# Building compute takes a long time and can't be parallelized within the product +# so lets build it first +all_product_files = all_product_files.sort_by { |product| product == 'products/compute' ? 0 : 1 } + # products_for_version entries are a hash of product definitions (:definitions) # and provider config (:overrides) for the product -products_for_version = [] -provider = nil # rubocop:disable Metrics/BlockLength -all_product_files.each do |product_name| +products_for_version = Parallel.map(all_product_files, in_processes: 8) do |product_name| product_override_path = '' product_override_path = File.join(override_dir, product_name, 'product.yaml') if override_dir product_yaml_path = File.join(product_name, 'product.yaml') @@ -255,7 +258,8 @@ pp provider_config if ENV['COMPILER_DEBUG'] if force_provider.nil? - provider = provider_config.provider.new(provider_config, product_api, version, start_time) + provider = \ + provider_config.provider.new(provider_config, product_api, version, start_time) else override_providers = { 'oics' => Provider::TerraformOiCS, @@ -273,9 +277,6 @@ override_providers[force_provider].new(provider_config, product_api, version, start_time) end - # provider_config is mutated by instantiating a provider - products_for_version.push(definitions: product_api, overrides: provider_config) - unless products_to_generate.include?(product_name) Google::LOGGER.info "#{product_name}: Not specified, skipping generation" next @@ -291,11 +292,20 @@ generate_code, generate_docs ) + + # provider_config is mutated by instantiating a provider. + # we need to preserve a single provider instance to use outside of this loop. + { definitions: product_api, overrides: provider_config, provider: provider } # rubocop:disable Style/HashSyntax end +products_for_version = products_for_version.compact # remove any nil values + # In order to only copy/compile files once per provider this must be called outside # of the products loop. This will get called with the provider from the final iteration # of the loop +final_product = products_for_version.compact.last +provider = final_product[:provider] + provider&.copy_common_files(output_path, generate_code, generate_docs) Google::LOGGER.info "Compiling common files for #{provider_name}" common_compile_file = "provider/#{provider_name}/common~compile.yaml" diff --git a/mmv1/products/alloydb/Backup.yaml b/mmv1/products/alloydb/Backup.yaml index 1131483c09cf..444acd072a17 100644 --- a/mmv1/products/alloydb/Backup.yaml +++ b/mmv1/products/alloydb/Backup.yaml @@ -30,16 +30,6 @@ timeouts: !ruby/object:Api::Timeouts async: !ruby/object:Api::OpAsync operation: !ruby/object:Api::OpAsync::Operation base_url: '{{op_id}}' - path: 'unused' - wait_ms: 0 # unused - result: !ruby/object:Api::OpAsync::Result - path: 'unused' - status: !ruby/object:Api::OpAsync::Status - path: 'unused' - allowed: [] - error: !ruby/object:Api::OpAsync::Error - path: 'unused' - message: 'unused' import_format: ['projects/{{project}}/locations/{{location}}/backups/{{backup_id}}'] autogen_async: true diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index 7fe42bae16bb..9eed5e54bbf6 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -48,6 +48,8 @@ import_format: 'projects/{{project}}/locations/{{location}}/clusters/{{cluster_id}}', '{{cluster_id}}', ] +# Skipping the sweeper because we need to force-delete clusters. +skip_sweeper: true autogen_async: true examples: - !ruby/object:Provider::Terraform::Examples @@ -212,6 +214,7 @@ properties: - !ruby/object:Api::Type::Array name: 'startTimes' required: true + custom_flatten: 'templates/terraform/custom_flatten/alloydb_cluster_input_automated_backup_policy_start_times_flatten.go.erb' description: | The times during the day to start a backup. At least one start time must be provided. The start times are assumed to be in UTC and to be an exact hour (e.g., 04:00:00). item_type: !ruby/object:Api::Type::NestedObject diff --git a/mmv1/products/alloydb/Instance.yaml b/mmv1/products/alloydb/Instance.yaml index 0acd336edc62..6a77c87b7258 100644 --- a/mmv1/products/alloydb/Instance.yaml +++ b/mmv1/products/alloydb/Instance.yaml @@ -44,6 +44,8 @@ async: !ruby/object:Api::OpAsync message: 'message' include_project: true import_format: ['{{cluster}}/instances/{{instance_id}}'] +# Skipping the sweeper because instances will be deleted during cluster sweeps +skip_sweeper: true autogen_async: true custom_code: !ruby/object:Provider::Terraform::CustomCode custom_import: templates/terraform/custom_import/alloydb_instance.go.erb diff --git a/mmv1/products/apigee/Organization.yaml b/mmv1/products/apigee/Organization.yaml index 3efb7676a37a..e6c0d808b8ad 100644 --- a/mmv1/products/apigee/Organization.yaml +++ b/mmv1/products/apigee/Organization.yaml @@ -64,6 +64,22 @@ examples: true # Resource creation race skip_vcr: true + - !ruby/object:Provider::Terraform::Examples + name: 'apigee_organization_cloud_basic_disable_vpc_peering' + skip_test: + true + # This is a more verbose version of the above that creates all + # the resources needed for the acceptance test. + - !ruby/object:Provider::Terraform::Examples + name: 'apigee_organization_cloud_basic_disable_vpc_peering_test' + primary_resource_id: 'org' + test_env_vars: + org_id: :ORG_ID + billing_account: :BILLING_ACCT + skip_docs: + true + # Resource creation race + skip_vcr: true - !ruby/object:Provider::Terraform::Examples name: 'apigee_organization_cloud_full' skip_test: @@ -83,6 +99,25 @@ examples: beta # Resource creation race skip_vcr: true + - !ruby/object:Provider::Terraform::Examples + name: 'apigee_organization_cloud_full_disable_vpc_peering' + skip_test: + true + # This is a more verbose version of the above that creates all + # the resources needed for the acceptance test. While all Apigee + # resources in this test are in the GA API, we depend on a service + # identity resource which is only available in the beta provider. + - !ruby/object:Provider::Terraform::Examples + name: 'apigee_organization_cloud_full_disable_vpc_peering_test' + primary_resource_id: 'org' + test_env_vars: + org_id: :ORG_ID + billing_account: :BILLING_ACCT + skip_docs: true + min_version: + beta + # Resource creation race + skip_vcr: true - !ruby/object:Provider::Terraform::Examples name: 'apigee_organization_retention_test' primary_resource_id: 'org' @@ -143,6 +178,14 @@ properties: Compute Engine network used for Service Networking to be peered with Apigee runtime instances. See [Getting started with the Service Networking API](https://cloud.google.com/service-infrastructure/docs/service-networking/getting-started). Valid only when `RuntimeType` is set to CLOUD. The value can be updated only when there are no runtime instances. For example: "default". + - !ruby/object:Api::Type::Boolean + name: 'disableVpcPeering' + description: | + Flag that specifies whether the VPC Peering through Private Google Access should be + disabled between the consumer network and Apigee. Required if an `authorizedNetwork` + on the consumer project is not provided, in which case the flag should be set to `true`. + Valid only when `RuntimeType` is set to CLOUD. The value must be set before the creation + of any Apigee runtime instance and can be updated only when there are no runtime instances. - !ruby/object:Api::Type::Enum name: 'runtimeType' description: | diff --git a/mmv1/products/cloudtasks/Queue.yaml b/mmv1/products/cloudtasks/Queue.yaml index 0988d7e29db2..511130752b00 100644 --- a/mmv1/products/cloudtasks/Queue.yaml +++ b/mmv1/products/cloudtasks/Queue.yaml @@ -172,6 +172,7 @@ properties: maxBackoff duration after it fails, if the queue's RetryConfig specifies that the task should be retried. default_from_api: true + diff_suppress_func: 'tpgresource.DurationDiffSuppress' - !ruby/object:Api::Type::String name: 'maxBackoff' description: | @@ -179,6 +180,7 @@ properties: maxBackoff duration after it fails, if the queue's RetryConfig specifies that the task should be retried. default_from_api: true + diff_suppress_func: 'tpgresource.DurationDiffSuppress' - !ruby/object:Api::Type::Integer name: 'maxDoublings' description: | diff --git a/mmv1/products/compute/Disk.yaml b/mmv1/products/compute/Disk.yaml index 84467c0539f4..ef9edfb89a19 100644 --- a/mmv1/products/compute/Disk.yaml +++ b/mmv1/products/compute/Disk.yaml @@ -428,6 +428,14 @@ properties: 'A resource policy applied to this disk for automatic snapshot creations.' custom_expand: 'templates/terraform/custom_expand/array_resourceref_with_validation.go.erb' + - !ruby/object:Api::Type::Boolean + name: 'enableConfidentialCompute' + description: | + Whether this disk is using confidential compute mode. + Note: Only supported on hyperdisk skus, disk_encryption_key is required when setting to true + min_version: beta + required: false + default_from_api: true - !ruby/object:Api::Type::Boolean name: 'multiWriter' description: | diff --git a/mmv1/products/compute/RegionBackendService.yaml b/mmv1/products/compute/RegionBackendService.yaml index ccb72397ecd3..fd0068cba262 100644 --- a/mmv1/products/compute/RegionBackendService.yaml +++ b/mmv1/products/compute/RegionBackendService.yaml @@ -110,6 +110,7 @@ custom_code: !ruby/object:Provider::Terraform::CustomCode constants: templates/terraform/constants/region_backend_service.go.erb encoder: templates/terraform/encoders/region_backend_service.go.erb decoder: templates/terraform/decoders/region_backend_service.go.erb + post_create: 'templates/terraform/post_create/compute_region_backend_service_security_policy.go.erb' custom_diff: [ 'customDiffRegionBackendService', ] @@ -1129,6 +1130,14 @@ properties: - :GRPC - :UNSPECIFIED default_from_api: true + - !ruby/object:Api::Type::String + name: 'securityPolicy' + min_version: beta + description: | + The security policy associated with this backend service. + update_verb: :POST + update_url: 'projects/{{project}}/regions/{{region}}/backendServices/{{name}}/setSecurityPolicy' + diff_suppress_func: 'tpgresource.CompareSelfLinkOrResourceName' - !ruby/object:Api::Type::Enum name: 'sessionAffinity' description: | diff --git a/mmv1/products/compute/ResourcePolicy.yaml b/mmv1/products/compute/ResourcePolicy.yaml index 325506ff420c..2fc5f561273e 100644 --- a/mmv1/products/compute/ResourcePolicy.yaml +++ b/mmv1/products/compute/ResourcePolicy.yaml @@ -20,6 +20,8 @@ has_self_link: true collection_url_key: 'items' description: | A policy that can be attached to a resource to specify or schedule actions on that resource. +references: !ruby/object:Api::Resource::ReferenceLinks + api: 'https://cloud.google.com/compute/docs/reference/rest/v1/resourcePolicies' async: !ruby/object:Api::OpAsync operation: !ruby/object:Api::OpAsync::Operation kind: 'compute#operation' @@ -152,7 +154,7 @@ properties: - !ruby/object:Api::Type::Integer name: 'daysInCycle' description: | - The number of days between snapshots. + Defines a schedule with units measured in days. The value determines how many days pass between the start of each cycle. Days in cycle for snapshot schedule policy must be 1. required: true - !ruby/object:Api::Type::String name: 'startTime' diff --git a/mmv1/products/compute/Subnetwork.yaml b/mmv1/products/compute/Subnetwork.yaml index e1daa37918a4..4461876ff554 100644 --- a/mmv1/products/compute/Subnetwork.yaml +++ b/mmv1/products/compute/Subnetwork.yaml @@ -366,7 +366,7 @@ properties: or the first time the subnet is updated into IPV4_IPV6 dual stack. If the ipv6_type is EXTERNAL then this subnet cannot enable direct path. - !ruby/object:Api::Type::String - name: 'ipv6CidrRange' + name: 'internalIpv6Prefix' output: true description: | The range of internal IPv6 addresses that are owned by this subnetwork. diff --git a/mmv1/products/dataplex/Task.yaml b/mmv1/products/dataplex/Task.yaml new file mode 100644 index 000000000000..3a4095794264 --- /dev/null +++ b/mmv1/products/dataplex/Task.yaml @@ -0,0 +1,503 @@ +# Copyright 2023 Google Inc. +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +--- !ruby/object:Api::Resource +name: 'Task' +base_url: 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}' +self_link: 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks?task_id={{task_id}}' +update_url: 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}' +delete_url: 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}' +update_verb: :PATCH +update_mask: true +description: | + A Dataplex task represents the work that you want Dataplex to do on a schedule. It encapsulates code, parameters, and the schedule. +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + timeouts: !ruby/object:Api::Timeouts + insert_minutes: 5 + update_minutes: 5 + delete_minutes: 5 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' +autogen_async: true +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Official Documentation': 'https://cloud.google.com/dataplex/docs' + api: 'https://cloud.google.com/dataplex/docs/reference/rest/v1/projects.locations.lakes.tasks' +import_format: ['projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}'] +iam_policy: !ruby/object:Api::Resource::IamPolicy + exclude: false + method_name_separator: ':' + parent_resource_attribute: 'task_id' + fetch_iam_policy_verb: :GET + import_format: + [ + 'projects/{{project}}/locations/{{location}}/lakes/{{lake}}/tasks/{{task_id}}', + '{{task_id}}', + ] +parameters: + - !ruby/object:Api::Type::String + name: 'location' + url_param_only: true + immutable: true + description: | + The location in which the task will be created in. + - !ruby/object:Api::Type::String + name: 'lake' + url_param_only: true + immutable: true + description: | + The lake in which the task will be created in. + - !ruby/object:Api::Type::String + name: 'taskId' + url_param_only: true + immutable: true + description: | + The task Id of the task. +properties: + - !ruby/object:Api::Type::String + name: 'name' + output: true + description: | + The relative resource name of the task, of the form: projects/{project_number}/locations/{locationId}/lakes/{lakeId}/ tasks/{name}. + - !ruby/object:Api::Type::String + name: 'uid' + output: true + description: | + System generated globally unique ID for the task. This ID will be different if the task is deleted and re-created with the same name. + - !ruby/object:Api::Type::Time + name: 'createTime' + output: true + description: | + The time when the task was created. + - !ruby/object:Api::Type::Time + name: 'updateTime' + output: true + description: | + The time when the task was last updated. + - !ruby/object:Api::Type::String + name: 'description' + description: | + User-provided description of the task. + - !ruby/object:Api::Type::String + name: 'displayName' + description: | + User friendly display name. + - !ruby/object:Api::Type::Enum + name: 'state' + output: true + description: | + Current state of the task. + values: + - :STATE_UNSPECIFIED + - :ACTIVE + - :CREATING + - :DELETING + - :ACTION_REQUIRED + - !ruby/object:Api::Type::KeyValuePairs + name: 'labels' + description: | + User-defined labels for the task. + - !ruby/object:Api::Type::NestedObject + name: 'triggerSpec' + required: true + description: | + Configuration for the cluster + properties: + - !ruby/object:Api::Type::Enum + name: 'type' + required: true + immutable: true + description: | + Trigger type of the user-specified Task + values: + - :ON_DEMAND + - :RECURRING + - !ruby/object:Api::Type::Time + name: 'startTime' + description: | + The first run of the task will be after this time. If not specified, the task will run shortly after being submitted if ON_DEMAND and based on the schedule if RECURRING. + - !ruby/object:Api::Type::Boolean + name: 'disabled' + description: | + Prevent the task from executing. This does not cancel already running tasks. It is intended to temporarily disable RECURRING tasks. + - !ruby/object:Api::Type::Integer + name: 'maxRetries' + description: | + Number of retry attempts before aborting. Set to zero to never attempt to retry a failed task. + - !ruby/object:Api::Type::String + name: 'schedule' + description: | + Cron schedule (https://en.wikipedia.org/wiki/Cron) for running tasks periodically. To explicitly set a timezone to the cron tab, apply a prefix in the cron tab: 'CRON_TZ=${IANA_TIME_ZONE}' or 'TZ=${IANA_TIME_ZONE}'. The ${IANA_TIME_ZONE} may only be a valid string from IANA time zone database. For example, CRON_TZ=America/New_York 1 * * * *, or TZ=America/New_York 1 * * * *. This field is required for RECURRING tasks. + - !ruby/object:Api::Type::NestedObject + name: 'executionSpec' + required: true + description: | + Configuration for the cluster + properties: + - !ruby/object:Api::Type::KeyValuePairs + name: 'args' + description: | + The arguments to pass to the task. The args can use placeholders of the format ${placeholder} as part of key/value string. These will be interpolated before passing the args to the driver. Currently supported placeholders: - ${taskId} - ${job_time} To pass positional args, set the key as TASK_ARGS. The value should be a comma-separated string of all the positional arguments. To use a delimiter other than comma, refer to https://cloud.google.com/sdk/gcloud/reference/topic/escaping. In case of other keys being present in the args, then TASK_ARGS will be passed as the last argument. An object containing a list of 'key': value pairs. Example: { 'name': 'wrench', 'mass': '1.3kg', 'count': '3' }. + - !ruby/object:Api::Type::String + name: 'serviceAccount' + required: true + description: | + Service account to use to execute a task. If not provided, the default Compute service account for the project is used. + - !ruby/object:Api::Type::String + name: 'project' + description: | + The project in which jobs are run. By default, the project containing the Lake is used. If a project is provided, the ExecutionSpec.service_account must belong to this project. + - !ruby/object:Api::Type::String + name: 'maxJobExecutionLifetime' + description: | + The maximum duration after which the job execution is expired. A duration in seconds with up to nine fractional digits, ending with 's'. Example: '3.5s'. + - !ruby/object:Api::Type::String + name: 'kmsKey' + description: | + The Cloud KMS key to use for encryption, of the form: projects/{project_number}/locations/{locationId}/keyRings/{key-ring-name}/cryptoKeys/{key-name}. + - !ruby/object:Api::Type::NestedObject + name: 'executionStatus' + output: true + description: | + Configuration for the cluster + properties: + - !ruby/object:Api::Type::String + name: 'updateTime' + output: true + description: | + Last update time of the status. + - !ruby/object:Api::Type::NestedObject + name: 'latestJob' + output: true + description: | + latest job execution. + properties: + - !ruby/object:Api::Type::String + name: 'name' + output: true + description: | + The relative resource name of the job, of the form: projects/{project_number}/locations/{locationId}/lakes/{lakeId}/tasks/{taskId}/jobs/{jobId}. + - !ruby/object:Api::Type::String + name: 'uid' + output: true + description: | + System generated globally unique ID for the job. + - !ruby/object:Api::Type::Time + name: 'startTime' + output: true + description: | + The time when the job was started. + - !ruby/object:Api::Type::Time + name: 'endTime' + output: true + description: | + The time when the job ended. + - !ruby/object:Api::Type::Enum + name: 'state' + output: true + description: | + Execution state for the job. + values: + - :STATE_UNSPECIFIED + - :RUNNING + - :CANCELLING + - :CANCELLED + - :SUCCEEDED + - :FAILED + - :ABORTED + - !ruby/object:Api::Type::Integer + name: 'retryCount' + output: true + description: | + The number of times the job has been retried (excluding the initial attempt). + - !ruby/object:Api::Type::Enum + name: 'service' + output: true + description: | + The underlying service running a job. + values: + - :SERVICE_UNSPECIFIED + - :DATAPROC + - !ruby/object:Api::Type::String + name: 'serviceJob' + output: true + description: | + The full resource name for the job run under a particular service. + - !ruby/object:Api::Type::String + name: 'message' + output: true + description: | + Additional information about the current state. + - !ruby/object:Api::Type::NestedObject + name: 'spark' + description: | + A service with manual scaling runs continuously, allowing you to perform complex initialization and rely on the state of its memory over time. + exactly_one_of: + - spark + - notebook + properties: + - !ruby/object:Api::Type::Array + name: 'fileUris' + description: | + Cloud Storage URIs of files to be placed in the working directory of each executor. + item_type: Api::Type::String + - !ruby/object:Api::Type::Array + name: 'archiveUris' + description: | + Cloud Storage URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. + item_type: Api::Type::String + - !ruby/object:Api::Type::NestedObject + name: 'infrastructureSpec' + description: | + Infrastructure specification for the execution. + properties: + - !ruby/object:Api::Type::NestedObject + name: 'batch' + description: | + Compute resources needed for a Task when using Dataproc Serverless. + properties: + - !ruby/object:Api::Type::Integer + name: 'executorsCount' + default_value: 2 + description: | + Total number of job executors. Executor Count should be between 2 and 100. [Default=2] + - !ruby/object:Api::Type::Integer + name: 'maxExecutorsCount' + default_value: 1000 + description: | + Max configurable executors. If maxExecutorsCount > executorsCount, then auto-scaling is enabled. Max Executor Count should be between 2 and 1000. [Default=1000] + - !ruby/object:Api::Type::NestedObject + name: 'containerImage' + description: | + Container Image Runtime Configuration. + properties: + - !ruby/object:Api::Type::String + name: 'image' + description: | + Container image to use. + - !ruby/object:Api::Type::Array + name: 'javaJars' + description: | + A list of Java JARS to add to the classpath. Valid input includes Cloud Storage URIs to Jar binaries. For example, gs://bucket-name/my/path/to/file.jar + item_type: Api::Type::String + - !ruby/object:Api::Type::Array + name: 'pythonPackages' + description: | + A list of python packages to be installed. Valid formats include Cloud Storage URI to a PIP installable library. For example, gs://bucket-name/my/path/to/lib.tar.gz + item_type: Api::Type::String + - !ruby/object:Api::Type::KeyValuePairs + name: 'properties' + description: | + Override to common configuration of open source components installed on the Dataproc cluster. The properties to set on daemon config files. Property keys are specified in prefix:property format, for example core:hadoop.tmp.dir. For more information, see Cluster properties. + - !ruby/object:Api::Type::NestedObject + name: 'vpcNetwork' + description: | + Vpc network. + properties: + - !ruby/object:Api::Type::Array + name: 'networkTags' + description: | + List of network tags to apply to the job. + item_type: Api::Type::String + - !ruby/object:Api::Type::String + name: 'network' + description: | + The Cloud VPC network in which the job is run. By default, the Cloud VPC network named Default within the project is used. + exactly_one_of: + - network + - subNetwork + - !ruby/object:Api::Type::String + name: 'subNetwork' + description: | + The Cloud VPC sub-network in which the job is run. + exactly_one_of: + - network + - subNetwork + - !ruby/object:Api::Type::String + name: 'mainJarFileUri' + description: | + The Cloud Storage URI of the jar file that contains the main class. The execution args are passed in as a sequence of named process arguments (--key=value). + exactly_one_of: + - mainJarFileUri + - mainClass + - pythonScriptFile + - sqlScriptFile + - sqlScript + - !ruby/object:Api::Type::String + name: 'mainClass' + description: | + The name of the driver's main class. The jar file that contains the class must be in the default CLASSPATH or specified in jar_file_uris. The execution args are passed in as a sequence of named process arguments (--key=value). + exactly_one_of: + - mainJarFileUri + - mainClass + - pythonScriptFile + - sqlScriptFile + - sqlScript + - !ruby/object:Api::Type::String + name: 'pythonScriptFile' + description: | + The Gcloud Storage URI of the main Python file to use as the driver. Must be a .py file. The execution args are passed in as a sequence of named process arguments (--key=value). + exactly_one_of: + - mainJarFileUri + - mainClass + - pythonScriptFile + - sqlScriptFile + - sqlScript + - !ruby/object:Api::Type::String + name: 'sqlScriptFile' + description: | + A reference to a query file. This can be the Cloud Storage URI of the query file or it can the path to a SqlScript Content. The execution args are used to declare a set of script variables (set key='value';). + exactly_one_of: + - mainJarFileUri + - mainClass + - pythonScriptFile + - sqlScriptFile + - sqlScript + - !ruby/object:Api::Type::String + name: 'sqlScript' + description: | + The query text. The execution args are used to declare a set of script variables (set key='value';). + exactly_one_of: + - mainJarFileUri + - mainClass + - pythonScriptFile + - sqlScriptFile + - sqlScript + - !ruby/object:Api::Type::NestedObject + name: 'notebook' + description: | + A service with manual scaling runs continuously, allowing you to perform complex initialization and rely on the state of its memory over time. + exactly_one_of: + - spark + - notebook + properties: + - !ruby/object:Api::Type::String + name: 'notebook' + required: true + description: | + Path to input notebook. This can be the Cloud Storage URI of the notebook file or the path to a Notebook Content. The execution args are accessible as environment variables (TASK_key=value). + - !ruby/object:Api::Type::NestedObject + name: 'infrastructureSpec' + description: | + Infrastructure specification for the execution. + properties: + - !ruby/object:Api::Type::NestedObject + name: 'batch' + description: | + Compute resources needed for a Task when using Dataproc Serverless. + properties: + - !ruby/object:Api::Type::Integer + name: 'executorsCount' + default_value: 2 + description: | + Total number of job executors. Executor Count should be between 2 and 100. [Default=2] + - !ruby/object:Api::Type::Integer + name: 'maxExecutorsCount' + default_value: 1000 + description: | + Max configurable executors. If maxExecutorsCount > executorsCount, then auto-scaling is enabled. Max Executor Count should be between 2 and 1000. [Default=1000] + - !ruby/object:Api::Type::NestedObject + name: 'containerImage' + description: | + Container Image Runtime Configuration. + properties: + - !ruby/object:Api::Type::String + name: 'image' + description: | + Container image to use. + - !ruby/object:Api::Type::Array + name: 'javaJars' + description: | + A list of Java JARS to add to the classpath. Valid input includes Cloud Storage URIs to Jar binaries. For example, gs://bucket-name/my/path/to/file.jar + item_type: Api::Type::String + - !ruby/object:Api::Type::Array + name: 'pythonPackages' + description: | + A list of python packages to be installed. Valid formats include Cloud Storage URI to a PIP installable library. For example, gs://bucket-name/my/path/to/lib.tar.gz + item_type: Api::Type::String + - !ruby/object:Api::Type::KeyValuePairs + name: 'properties' + description: | + Override to common configuration of open source components installed on the Dataproc cluster. The properties to set on daemon config files. Property keys are specified in prefix:property format, for example core:hadoop.tmp.dir. For more information, see Cluster properties. + - !ruby/object:Api::Type::NestedObject + name: 'vpcNetwork' + description: | + Vpc network. + properties: + - !ruby/object:Api::Type::Array + name: 'networkTags' + description: | + List of network tags to apply to the job. + item_type: Api::Type::String + - !ruby/object:Api::Type::String + name: 'network' + description: | + The Cloud VPC network in which the job is run. By default, the Cloud VPC network named Default within the project is used. + exactly_one_of: + - network + - subNetwork + - !ruby/object:Api::Type::String + name: 'subNetwork' + description: | + The Cloud VPC sub-network in which the job is run. + exactly_one_of: + - network + - subNetwork + - !ruby/object:Api::Type::Array + name: 'fileUris' + description: | + Cloud Storage URIs of files to be placed in the working directory of each executor. + item_type: Api::Type::String + - !ruby/object:Api::Type::Array + name: 'archiveUris' + description: | + Cloud Storage URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. + item_type: Api::Type::String +examples: + - !ruby/object:Provider::Terraform::Examples + name: 'dataplex_task_basic' + primary_resource_id: 'example' + primary_resource_name: + 'fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), + fmt.Sprintf("tf-test-task%s", context["random_suffix"])' + test_env_vars: + project_name: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: 'dataplex_task_spark' + primary_resource_id: 'example_spark' + primary_resource_name: + 'fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), + fmt.Sprintf("tf-test-task%s", context["random_suffix"])' + test_env_vars: + project_name: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: 'dataplex_task_notebook' + primary_resource_id: 'example_notebook' + primary_resource_name: + 'fmt.Sprintf("tf-test-lake%s", context["random_suffix"]), + fmt.Sprintf("tf-test-task%s", context["random_suffix"])' + test_env_vars: + project_name: :PROJECT_NAME diff --git a/mmv1/products/dataplex/product.yaml b/mmv1/products/dataplex/product.yaml index 1097808e49d6..7e6dea430ca9 100644 --- a/mmv1/products/dataplex/product.yaml +++ b/mmv1/products/dataplex/product.yaml @@ -23,4 +23,4 @@ scopes: apis_required: - !ruby/object:Api::Product::ApiReference name: Cloud Dataplex API - url: https://cloud.google.com/dataplex/docs/reference/rest/ + url: https://console.cloud.google.com/apis/library/dataplex.googleapis.com diff --git a/mmv1/products/firestore/Database.yaml b/mmv1/products/firestore/Database.yaml index b078b61de145..5fa7e8ba5290 100644 --- a/mmv1/products/firestore/Database.yaml +++ b/mmv1/products/firestore/Database.yaml @@ -18,8 +18,7 @@ create_url: 'projects/{{project}}/databases?databaseId={{name}}' update_verb: :PATCH update_mask: true description: | - A Cloud Firestore Database. Currently only one database is allowed per - Cloud project; this database must have a `database_id` of '(default)'. + A Cloud Firestore Database. If you wish to use Firestore with App Engine, use the [`google_app_engine_application`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/app_engine_application) @@ -54,19 +53,31 @@ import_format: - '{{project}}/{{name}}' - '{{name}}' examples: + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_default_database' + primary_resource_id: 'database' + pull_external: true + test_env_vars: + org_id: :ORG_ID + ignore_read_extra: + - project + - etag + vars: + project_id: 'my-project' - !ruby/object:Provider::Terraform::Examples name: 'firestore_database' primary_resource_id: 'database' pull_external: true test_env_vars: org_id: :ORG_ID + billing_account: :BILLING_ACCT ignore_read_extra: - project - etag vars: project_id: 'my-project' - !ruby/object:Provider::Terraform::Examples - name: 'firestore_database_datastore_mode' + name: 'firestore_default_database_in_datastore_mode' primary_resource_id: 'datastore_mode_database' pull_external: true test_env_vars: @@ -76,6 +87,18 @@ examples: - etag vars: project_id: 'my-project' + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_database_in_datastore_mode' + primary_resource_id: 'database' + pull_external: true + test_env_vars: + org_id: :ORG_ID + billing_account: :BILLING_ACCT + ignore_read_extra: + - project + - etag + vars: + project_id: 'my-project' properties: - !ruby/object:Api::Type::String name: name diff --git a/mmv1/products/gkebackup/BackupPlan.yaml b/mmv1/products/gkebackup/BackupPlan.yaml index 531dee83be93..28172b41460f 100644 --- a/mmv1/products/gkebackup/BackupPlan.yaml +++ b/mmv1/products/gkebackup/BackupPlan.yaml @@ -260,3 +260,13 @@ properties: output: true description: | The number of Kubernetes Pods backed up in the last successful Backup created via this BackupPlan. + - !ruby/object:Api::Type::String + name: state + output: true + description: | + The State of the BackupPlan. + - !ruby/object:Api::Type::String + name: stateReason + output: true + description: | + Detailed description of why BackupPlan is in its current state. diff --git a/mmv1/products/healthcare/FhirStore.yaml b/mmv1/products/healthcare/FhirStore.yaml index 195ad7134e2a..4bd493a7ebaf 100644 --- a/mmv1/products/healthcare/FhirStore.yaml +++ b/mmv1/products/healthcare/FhirStore.yaml @@ -110,6 +110,15 @@ properties: - :DSTU2 - :STU3 - :R4 + - !ruby/object:Api::Type::Enum + name: complexDataTypeReferenceParsing + description: | + Enable parsing of references within complex FHIR data types such as Extensions. If this value is set to ENABLED, then features like referential integrity and Bundle reference rewriting apply to all references. If this flag has not been specified the behavior of the FHIR store will not change, references in complex data types will not be parsed. New stores will have this value set to ENABLED by default after a notification period. Warning: turning on this flag causes processing existing resources to fail if they contain references to non-existent resources. + default_from_api: true + values: + - :COMPLEX_DATA_TYPE_REFERENCE_PARSING_UNSPECIFIED + - :DISABLED + - :ENABLED - !ruby/object:Api::Type::Boolean name: 'enableUpdateCreate' description: | diff --git a/mmv1/products/looker/Instance.yaml b/mmv1/products/looker/Instance.yaml new file mode 100644 index 000000000000..b830b54c7ac8 --- /dev/null +++ b/mmv1/products/looker/Instance.yaml @@ -0,0 +1,405 @@ +# Copyright 2023 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Resource +name: 'Instance' +base_url: projects/{{project}}/locations/{{region}}/instances +create_url: projects/{{project}}/locations/{{region}}/instances?instanceId={{name}} +update_verb: :PATCH +update_mask: true +description: | + A Google Cloud Looker instance. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Create a Looker (Google Cloud core) instance': 'https://cloud.google.com/looker/docs/looker-core-instance-create' + 'Configure a Looker (Google Cloud core) instance': 'https://cloud.google.com/looker/docs/looker-core-instance-setup' + api: 'https://cloud.google.com/looker/docs/reference/rest/v1/projects.locations.instances' +timeouts: !ruby/object:Api::Timeouts + insert_minutes: 90 + update_minutes: 90 + delete_minutes: 90 +autogen_async: true +error_abort_predicates: ['transport_tpg.Is429QuotaError'] +examples: + - !ruby/object:Provider::Terraform::Examples + name: 'looker_instance_basic' + primary_resource_id: 'looker-instance' + vars: + instance_name: 'my-instance' + client_id: 'my-client-id' + client_secret: 'my-client-secret' + - !ruby/object:Provider::Terraform::Examples + name: 'looker_instance_full' + primary_resource_id: 'looker-instance' + vars: + instance_name: 'my-instance' + client_id: 'my-client-id' + client_secret: 'my-client-secret' + - !ruby/object:Provider::Terraform::Examples + name: 'looker_instance_enterprise_full' + primary_resource_id: 'looker-instance' + vars: + network_name: 'looker-network' + kms_key_ring_name: 'looker-kms-ring' + kms_key_name: 'looker-kms-key' + address_name: 'looker-range' + instance_name: 'my-instance' + client_id: 'my-client-id' + client_secret: 'my-client-secret' + test_vars_overrides: + kms_key_name: 'acctest.BootstrapKMSKeyInLocation(t, "us-central1").CryptoKey.Name' +parameters: + - !ruby/object:Api::Type::String + name: 'region' + description: | + The name of the Looker region of the instance. + immutable: true + url_param_only: true + default_from_api: true +properties: + # Admin Settings Object + - !ruby/object:Api::Type::NestedObject + name: adminSettings + description: | + Looker instance Admin settings. + update_mask_fields: + - 'admin_settings.allowed_email_domains' + properties: + - !ruby/object:Api::Type::Array + name: 'allowedEmailDomains' + item_type: Api::Type::String + description: | + Email domain allowlist for the instance. + + Define the email domains to which your users can deliver Looker (Google Cloud core) content. + Updating this list will restart the instance. Updating the allowed email domains from terraform + means the value provided will be considered as the entire list and not an amendment to the + existing list of allowed email domains. + # Admin Settings Object - End + - !ruby/object:Api::Type::String + name: consumerNetwork + description: | + Network name in the consumer project in the format of: projects/{project}/global/networks/{network} + Note that the consumer network may be in a different GCP project than the consumer + project that is hosting the Looker Instance. + - !ruby/object:Api::Type::Time + name: createTime + description: | + The time the instance was created in RFC3339 UTC "Zulu" format, + accurate to nanoseconds. + output: true + # Deny Maintenance Period Object + - !ruby/object:Api::Type::NestedObject + name: denyMaintenancePeriod + description: | + Maintenance denial period for this instance. + + You must allow at least 14 days of maintenance availability + between any two deny maintenance periods. + properties: + - !ruby/object:Api::Type::NestedObject + name: 'startDate' + required: true + description: | + Required. Start date of the deny maintenance period + properties: + - !ruby/object:Api::Type::Integer + name: 'year' + description: | + Year of the date. Must be from 1 to 9999, or 0 to specify a date without + a year. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,10000)' + - !ruby/object:Api::Type::Integer + name: 'month' + description: | + Month of a year. Must be from 1 to 12, or 0 to specify a year without a + month and day. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,13)' + - !ruby/object:Api::Type::Integer + name: 'day' + description: | + Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + to specify a year by itself or a year and month where the day isn't significant. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,32)' + - !ruby/object:Api::Type::NestedObject + name: 'endDate' + required: true + description: | + Required. Start date of the deny maintenance period + properties: + - !ruby/object:Api::Type::Integer + name: 'year' + description: | + Year of the date. Must be from 1 to 9999, or 0 to specify a date without + a year. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,10000)' + - !ruby/object:Api::Type::Integer + name: 'month' + description: | + Month of a year. Must be from 1 to 12, or 0 to specify a year without a + month and day. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,13)' + - !ruby/object:Api::Type::Integer + name: 'day' + description: | + Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + to specify a year by itself or a year and month where the day isn't significant. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,32)' + + + - !ruby/object:Api::Type::NestedObject + name: 'time' + required: true + description: | + Required. Start time of the window in UTC time. + properties: + - !ruby/object:Api::Type::Integer + name: 'hours' + description: | + Hours of day in 24 hour format. Should be from 0 to 23. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,23)' + - !ruby/object:Api::Type::Integer + name: 'minutes' + description: | + Minutes of hour of day. Must be from 0 to 59. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,60)' + - !ruby/object:Api::Type::Integer + name: 'seconds' + description: | + Seconds of minutes of the time. Must normally be from 0 to 59. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,60)' + - !ruby/object:Api::Type::Integer + name: 'nanos' + description: | + Fractions of seconds in nanoseconds. Must be from 0 to 999,999,999. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,999999999)' + + # Deny Maintenance Period Object - End + - !ruby/object:Api::Type::String + name: egressPublicIp + description: | + Public Egress IP (IPv4). + output: true + # Encryption Config Object + - !ruby/object:Api::Type::NestedObject + name: encryptionConfig + default_from_api: true + description: | + Looker instance encryption settings. + properties: + - !ruby/object:Api::Type::String + name: 'kmsKeyName' + description: | + Name of the customer managed encryption key (CMEK) in KMS. + - !ruby/object:Api::Type::Enum + name: 'kmsKeyState' + output: true + description: | + Status of the customer managed encryption key (CMEK) in KMS. + values: + - :VALID + - :REVOKED + - !ruby/object:Api::Type::String + name: 'kmsKeyNameVersion' + output: true + description: | + Full name and version of the CMEK key currently in use to encrypt Looker data. + # Encryption Config Object - End + - !ruby/object:Api::Type::String + name: ingressPrivateIp + description: | + Private Ingress IP (IPv4). + output: true + - !ruby/object:Api::Type::String + name: ingressPublicIp + description: | + Public Ingress IP (IPv4). + output: true + - !ruby/object:Api::Type::String + name: lookerVersion + description: | + The Looker version that the instance is using. + output: true + - !ruby/object:Api::Type::String + name: lookerUri + description: | + Looker instance URI which can be used to access the Looker Instance UI. + output: true + + # Maintenance Window Object + - !ruby/object:Api::Type::NestedObject + name: maintenanceWindow + description: | + Maintenance window for an instance. + + Maintenance of your instance takes place once a month, and will require + your instance to be restarted during updates, which will temporarily + disrupt service. + properties: + - !ruby/object:Api::Type::Enum + name: 'dayOfWeek' + required: true + description: | + Required. Day of the week for this MaintenanceWindow (in UTC). + + - MONDAY: Monday + - TUESDAY: Tuesday + - WEDNESDAY: Wednesday + - THURSDAY: Thursday + - FRIDAY: Friday + - SATURDAY: Saturday + - SUNDAY: Sunday + values: + - :MONDAY + - :TUESDAY + - :WEDNESDAY + - :THURSDAY + - :FRIDAY + - :SATURDAY + - :SUNDAY + - !ruby/object:Api::Type::NestedObject + name: 'startTime' + required: true + description: | + Required. Start time of the window in UTC time. + properties: + - !ruby/object:Api::Type::Integer + name: 'hours' + description: | + Hours of day in 24 hour format. Should be from 0 to 23. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,23)' + - !ruby/object:Api::Type::Integer + name: 'minutes' + description: | + Minutes of hour of day. Must be from 0 to 59. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,60)' + - !ruby/object:Api::Type::Integer + name: 'seconds' + description: | + Seconds of minutes of the time. Must normally be from 0 to 59. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,60)' + - !ruby/object:Api::Type::Integer + name: 'nanos' + description: | + Fractions of seconds in nanoseconds. Must be from 0 to 999,999,999. + validation: !ruby/object:Provider::Terraform::Validation + function: 'validation.IntBetween(0,999999999)' + # Maintenance Window Object - End + - !ruby/object:Api::Type::String + name: name + description: | + The ID of the instance or a fully qualified identifier for the instance. + required: true + immutable: true + url_param_only: true + validation: !ruby/object:Provider::Terraform::Validation + regex: '^[a-z][a-z0-9-]{0,39}[a-z0-9]$' + # Oauth Object + - !ruby/object:Api::Type::NestedObject + name: oauthConfig + ignore_read: true + description: | + Looker Instance OAuth login settings. + properties: + - !ruby/object:Api::Type::String + name: 'clientId' + required: true + description: | + The client ID for the Oauth config. + - !ruby/object:Api::Type::String + name: 'clientSecret' + required: true + description: | + The client secret for the Oauth config. + # Oauth Object - End + - !ruby/object:Api::Type::Enum + name: platformEdition + description: | + Platform editions for a Looker instance. Each edition maps to a set of instance features, like its size. Must be one of these values: + - LOOKER_CORE_TRIAL: trial instance + - LOOKER_CORE_STANDARD: pay as you go standard instance + - LOOKER_CORE_STANDARD_ANNUAL: subscription standard instance + - LOOKER_CORE_ENTERPRISE_ANNUAL: subscription enterprise instance + - LOOKER_CORE_EMBED_ANNUAL: subscription embed instance + - LOOKER_MODELER: standalone modeling service + values: + - :LOOKER_CORE_TRIAL + - :LOOKER_CORE_STANDARD + - :LOOKER_CORE_STANDARD_ANNUAL + - :LOOKER_CORE_ENTERPRISE_ANNUAL + - :LOOKER_CORE_EMBED_ANNUAL + - :LOOKER_MODELER + default_value: :LOOKER_CORE_TRIAL + immutable: true + - !ruby/object:Api::Type::Boolean + name: privateIpEnabled + description: | + Whether private IP is enabled on the Looker instance. + default_value: false + - !ruby/object:Api::Type::Boolean + name: publicIpEnabled + description: | + Whether public IP is enabled on the Looker instance. + default_value: true + - !ruby/object:Api::Type::String + name: reservedRange + description: | + Name of a reserved IP address range within the consumer network, to be used for + private service access connection. User may or may not specify this in a request. + - !ruby/object:Api::Type::Time + name: updateTime + description: | + The time the instance was updated in RFC3339 UTC "Zulu" format, + accurate to nanoseconds. + output: true + # UserMetadata Object + - !ruby/object:Api::Type::NestedObject + name: userMetadata + description: | + Metadata about users for a Looker instance. + + These settings are only available when platform edition LOOKER_CORE_STANDARD is set. + + There are ten Standard and two Developer users included in the cost of the product. + You can allocate additional Standard, Viewer, and Developer users for this instance. + It is an optional step and can be modified later. + + With the Standard edition of Looker (Google Cloud core), you can provision up to 50 + total users, distributed across Viewer, Standard, and Developer. + properties: + - !ruby/object:Api::Type::Integer + name: 'additionalViewerUserCount' + description: | + Number of additional Viewer Users to allocate to the Looker Instance. + - !ruby/object:Api::Type::Integer + name: 'additionalStandardUserCount' + description: | + Number of additional Standard Users to allocate to the Looker Instance. + - !ruby/object:Api::Type::Integer + name: 'additionalDeveloperUserCount' + description: | + Number of additional Developer Users to allocate to the Looker Instance. + # UserMetadata Object - End diff --git a/mmv1/products/looker/product.yaml b/mmv1/products/looker/product.yaml new file mode 100644 index 000000000000..4d3d1aba79e1 --- /dev/null +++ b/mmv1/products/looker/product.yaml @@ -0,0 +1,43 @@ +# Copyright 2023 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Product +name: Looker +display_name: Looker (Google Cloud core) +versions: + - !ruby/object:Api::Product::Version + name: ga + base_url: https://looker.googleapis.com/v1/ +scopes: + - https://www.googleapis.com/auth/cloud-platform +apis_required: + - !ruby/object:Api::Product::ApiReference + name: Looker API + url: https://console.cloud.google.com/apis/library/looker.googleapis.com/ +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: 'name' + base_url: '{{op_id}}' + wait_ms: 1000 + result: !ruby/object:Api::OpAsync::Result + path: 'response' + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: 'done' + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: 'error' + message: 'message' diff --git a/mmv1/products/monitoring/MonitoredProject.yaml b/mmv1/products/monitoring/MonitoredProject.yaml index b8dc6542cb06..919e7567b19f 100644 --- a/mmv1/products/monitoring/MonitoredProject.yaml +++ b/mmv1/products/monitoring/MonitoredProject.yaml @@ -17,9 +17,9 @@ base_url: v1/locations/global/metricsScopes create_url: v1/locations/global/metricsScopes/{{metrics_scope}}/projects delete_url: v1/locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}} self_link: v1/locations/global/metricsScopes/{{metrics_scope}} -id_format: v1/locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}} -import_format: - - v1/locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}} +id_format: locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}} +schema_version: 1 +state_upgraders: true references: !ruby/object:Api::Resource::ReferenceLinks guides: 'Official Documentation': 'https://cloud.google.com/monitoring/settings/manage-api' @@ -27,12 +27,14 @@ references: !ruby/object:Api::Resource::ReferenceLinks nested_query: !ruby/object:Api::Resource::NestedQuery keys: - monitoredProjects -legacy_long_form_project: true description: "A [project being monitored](https://cloud.google.com/monitoring/settings/multiple-projects#create-multi) by a Metrics Scope." immutable: true +error_retry_predicates: ['transport_tpg.IsMonitoringPermissionError'] custom_code: !ruby/object:Provider::Terraform::CustomCode + custom_import: templates/terraform/custom_import/monitoring_monitored_project.go.erb encoder: templates/terraform/encoders/monitoring_monitored_project.go.erb decoder: templates/terraform/decoders/monitoring_monitored_project.go.erb + pre_read: templates/terraform/pre_read/monitoring_monitored_project.go.erb test_check_destroy: templates/terraform/custom_check_destroy/monitoring_monitored_project.go.erb examples: - !ruby/object:Provider::Terraform::Examples @@ -43,17 +45,29 @@ examples: test_env_vars: org_id: :ORG_ID project_id: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: 'monitoring_monitored_project_long_form' + primary_resource_id: 'primary' + vars: + monitored_project: 'm-id' + test_env_vars: + org_id: :ORG_ID + project_id: :PROJECT_NAME + skip_docs: true parameters: - !ruby/object:Api::Type::String name: metricsScope description: 'Required. The resource name of the existing Metrics Scope that will monitor this project. Example: locations/global/metricsScopes/{SCOPING_PROJECT_ID_OR_NUMBER}' url_param_only: true required: true + diff_suppress_func: 'tpgresource.CompareResourceNames' + ignore_read: true properties: - !ruby/object:Api::Type::String name: name description: 'Immutable. The resource name of the `MonitoredProject`. On input, the resource name includes the scoping project ID and monitored project ID. On output, it contains the equivalent project numbers. Example: `locations/global/metricsScopes/{SCOPING_PROJECT_ID_OR_NUMBER}/projects/{MONITORED_PROJECT_ID_OR_NUMBER}`' required: true + diff_suppress_func: 'tpgresource.CompareResourceNames' - !ruby/object:Api::Type::String name: createTime description: Output only. The time when this `MonitoredProject` was created. diff --git a/mmv1/products/networkservices/EdgeCacheService.yaml b/mmv1/products/networkservices/EdgeCacheService.yaml index 8774a37eb069..ff77b8df406e 100644 --- a/mmv1/products/networkservices/EdgeCacheService.yaml +++ b/mmv1/products/networkservices/EdgeCacheService.yaml @@ -515,7 +515,7 @@ properties: Names of query string parameters to include in cache keys. All other parameters will be excluded. Either specify includedQueryParameters or excludedQueryParameters, not both. '&' and '=' will be percent encoded and not treated as delimiters. - max_size: 10 + max_size: 20 item_type: Api::Type::String - !ruby/object:Api::Type::Array name: excludedQueryParameters @@ -523,7 +523,7 @@ properties: Names of query string parameters to exclude from cache keys. All other parameters will be included. Either specify includedQueryParameters or excludedQueryParameters, not both. '&' and '=' will be percent encoded and not treated as delimiters. - max_size: 10 + max_size: 20 item_type: Api::Type::String - !ruby/object:Api::Type::Array name: includedHeaderNames diff --git a/mmv1/products/vpcaccess/Connector.yaml b/mmv1/products/vpcaccess/Connector.yaml index c2034fc2bf3a..76d3a514e0a8 100644 --- a/mmv1/products/vpcaccess/Connector.yaml +++ b/mmv1/products/vpcaccess/Connector.yaml @@ -15,13 +15,14 @@ name: 'Connector' kind: 'vpcaccess#Connector' description: 'Serverless VPC Access connector resource.' -immutable: true base_url: projects/{{project}}/locations/{{region}}/connectors create_url: projects/{{project}}/locations/{{region}}/connectors?connectorId={{name}} +update_verb: :PATCH references: !ruby/object:Api::Resource::ReferenceLinks guides: 'Configuring Serverless VPC Access': 'https://cloud.google.com/vpc/docs/configure-serverless-vpc-access' api: 'https://cloud.google.com/vpc/docs/reference/vpcaccess/rest/v1/projects.locations.connectors' +update_mask: true async: !ruby/object:Api::OpAsync operation: !ruby/object:Api::OpAsync::Operation path: 'name' @@ -55,6 +56,8 @@ custom_code: !ruby/object:Provider::Terraform::CustomCode encoder: templates/terraform/encoders/no_send_name.go.erb post_create: templates/terraform/post_create/sleep.go.erb decoder: templates/terraform/decoders/long_name_to_self_link.go.erb + constants: templates/terraform/constants/connector.erb + resource_definition: templates/terraform/resource_definition/connector.erb parameters: - !ruby/object:Api::Type::String name: 'region' @@ -68,6 +71,7 @@ properties: name: name description: | The name of the resource (Max 25 characters). + immutable: true required: true custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' - !ruby/object:Api::Type::String @@ -77,6 +81,7 @@ properties: exactly_one_of: - network - subnet.0.name + immutable: true custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb' custom_expand: 'templates/terraform/custom_expand/resource_from_self_link.go.erb' diff_suppress_func: 'tpgresource.CompareResourceNames' @@ -87,6 +92,7 @@ properties: The range of internal addresses that follows RFC 4632 notation. Example: `10.132.0.0/28`. required_with: - network + immutable: true - !ruby/object:Api::Type::Enum name: state description: | @@ -102,34 +108,36 @@ properties: name: machineType description: | Machine type of VM Instance underlying connector. Default is e2-micro + immutable: false default_value: e2-micro - !ruby/object:Api::Type::Integer name: minThroughput description: | Minimum throughput of the connector in Mbps. Default and min is 200. - default_value: 200 + immutable: true + default_from_api: true validation: !ruby/object:Provider::Terraform::Validation - function: 'validation.IntBetween(200, 1000)' + function: 'validation.IntBetween(200, 900)' - !ruby/object:Api::Type::Integer name: minInstances description: | Minimum value of instances in autoscaling group underlying the connector. + immutable: false default_from_api: true - !ruby/object:Api::Type::Integer name: maxInstances description: | Maximum value of instances in autoscaling group underlying the connector. + immutable: false default_from_api: true - !ruby/object:Api::Type::Integer name: maxThroughput - # The API documentation says this will default to 200, but when I tried that I got an error that the minimum - # throughput must be lower than the maximum. The console defaults to 1000, so I changed it to that. - # API returns 300 if it is not sent description: | - Maximum throughput of the connector in Mbps, must be greater than `min_throughput`. Default is 300. - default_value: 300 + Maximum throughput of the connector in Mbps, must be greater than `min_throughput`. Default is 1000. + immutable: true + default_from_api: true validation: !ruby/object:Provider::Terraform::Validation - function: 'validation.IntBetween(200, 1000)' + function: 'validation.IntBetween(300, 1000)' - !ruby/object:Api::Type::String name: 'selfLink' description: | diff --git a/mmv1/provider/terraform_validator.rb b/mmv1/provider/terraform_validator.rb index c3ae1533a3f7..74d19393d0e5 100644 --- a/mmv1/provider/terraform_validator.rb +++ b/mmv1/provider/terraform_validator.rb @@ -472,6 +472,10 @@ def replace_import_path(output_folder, target) %r{(? +func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // If no start times exist, that means we take backups at midnight. This is represented as 0's all around. + return append(transformed, map[string]interface{}{}) + } + transformed = append(transformed, map[string]interface{}{ + "hours": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesHours(original["hours"], d, config), + "minutes": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesMinutes(original["minutes"], d, config), + "seconds": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesSeconds(original["seconds"], d, config), + "nanos": flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesNanos(original["nanos"], d, config), + }) + } + return transformed +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesHours(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesMinutes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesSeconds(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenAlloydbClusterAutomatedBackupPolicyWeeklyScheduleStartTimesNanos(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} \ No newline at end of file diff --git a/mmv1/templates/terraform/custom_import/monitoring_monitored_project.go.erb b/mmv1/templates/terraform/custom_import/monitoring_monitored_project.go.erb new file mode 100644 index 000000000000..8510dd4817ef --- /dev/null +++ b/mmv1/templates/terraform/custom_import/monitoring_monitored_project.go.erb @@ -0,0 +1,37 @@ +<%- # the license inside this block applies to this file + # Copyright 2023 Google Inc. + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-%> +name := d.Get("name").(string) +name = tpgresource.GetResourceNameFromSelfLink(name) +d.Set("name", name) +metricsScope := d.Get("metrics_scope").(string) +metricsScope = tpgresource.GetResourceNameFromSelfLink(metricsScope) +d.Set("metrics_scope", metricsScope) +config := meta.(*transport_tpg.Config) +if err := tpgresource.ParseImportId([]string{ + "locations/global/metricsScopes/(?P[^/]+)/projects/(?P[^/]+)", + "v1/locations/global/metricsScopes/(?P[^/]+)/projects/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", +}, d, config); err != nil { + return nil, err +} + +// Replace import id for the resource id +id, err := tpgresource.ReplaceVars(d, config, "locations/global/metricsScopes/{{metrics_scope}}/projects/{{name}}") +if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) +} +d.SetId(id) + +return []*schema.ResourceData{d}, nil diff --git a/mmv1/templates/terraform/encoders/monitoring_monitored_project.go.erb b/mmv1/templates/terraform/encoders/monitoring_monitored_project.go.erb index 3736b6609811..94012980b429 100644 --- a/mmv1/templates/terraform/encoders/monitoring_monitored_project.go.erb +++ b/mmv1/templates/terraform/encoders/monitoring_monitored_project.go.erb @@ -14,7 +14,9 @@ -%> name := d.Get("name").(string) name = tpgresource.GetResourceNameFromSelfLink(name) +d.Set("name", name) metricsScope := d.Get("metrics_scope").(string) metricsScope = tpgresource.GetResourceNameFromSelfLink(metricsScope) +d.Set("metrics_scope", metricsScope) obj["name"] = fmt.Sprintf("locations/global/metricsScopes/%s/projects/%s", metricsScope, name) return obj, nil diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_basic.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_basic.tf.erb index 18c24789e9ea..a6fd87e08a12 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_basic.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_basic.tf.erb @@ -1,7 +1,7 @@ resource "google_alloydb_cluster" "<%= ctx[:primary_resource_id] %>" { cluster_id = "<%= ctx[:vars]['alloydb_cluster_name'] %>" location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + network = google_compute_network.default.id } data "google_project" "project" {} diff --git a/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb b/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb index f9821307710e..2378c8e340b8 100644 --- a/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_cluster_full.tf.erb @@ -1,7 +1,7 @@ resource "google_alloydb_cluster" "<%= ctx[:primary_resource_id] %>" { cluster_id = "<%= ctx[:vars]['alloydb_cluster_name'] %>" location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + network = google_compute_network.default.id initial_user { user = "<%= ctx[:vars]['alloydb_cluster_name'] %>" diff --git a/mmv1/templates/terraform/examples/alloydb_instance_basic.tf.erb b/mmv1/templates/terraform/examples/alloydb_instance_basic.tf.erb index 5c9a0a6dfec2..2d3f52e2ebb5 100644 --- a/mmv1/templates/terraform/examples/alloydb_instance_basic.tf.erb +++ b/mmv1/templates/terraform/examples/alloydb_instance_basic.tf.erb @@ -13,7 +13,7 @@ resource "google_alloydb_instance" "<%= ctx[:primary_resource_id] %>" { resource "google_alloydb_cluster" "<%= ctx[:primary_resource_id] %>" { cluster_id = "<%= ctx[:vars]['alloydb_cluster_name'] %>" location = "us-central1" - network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + network = google_compute_network.default.id initial_user { password = "<%= ctx[:vars]['alloydb_cluster_name'] %>" diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering.tf.erb b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering.tf.erb new file mode 100644 index 000000000000..ca2afe9ae26c --- /dev/null +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering.tf.erb @@ -0,0 +1,9 @@ +data "google_client_config" "current" {} + +resource "google_apigee_organization" "org" { + description = "Terraform-provisioned basic Apigee Org without VPC Peering." + analytics_region = "us-central1" + project_id = data.google_client_config.current.project + disable_vpc_peering = true +} + diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering_test.tf.erb b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering_test.tf.erb new file mode 100644 index 000000000000..a0b0e6762698 --- /dev/null +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_disable_vpc_peering_test.tf.erb @@ -0,0 +1,21 @@ +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" + billing_account = "<%= ctx[:test_env_vars]['billing_account'] %>" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_apigee_organization" "<%= ctx[:primary_resource_id] %>" { + description = "Terraform-provisioned basic Apigee Org without VPC Peering." + analytics_region = "us-central1" + project_id = google_project.project.project_id + disable_vpc_peering = true + depends_on = [ + google_project_service.apigee, + ] +} diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering.tf.erb b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering.tf.erb new file mode 100644 index 000000000000..d393b02985f3 --- /dev/null +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering.tf.erb @@ -0,0 +1,43 @@ +data "google_client_config" "current" {} + +resource "google_kms_key_ring" "apigee_keyring" { + name = "apigee-keyring" + location = "us-central1" +} + +resource "google_kms_crypto_key" "apigee_key" { + name = "apigee-key" + key_ring = google_kms_key_ring.apigee_keyring.id + + lifecycle { + prevent_destroy = true + } +} + +resource "google_project_service_identity" "apigee_sa" { + provider = google-beta + project = google_project.project.project_id + service = google_project_service.apigee.service +} + +resource "google_kms_crypto_key_iam_binding" "apigee_sa_keyuser" { + crypto_key_id = google_kms_crypto_key.apigee_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:${google_project_service_identity.apigee_sa.email}", + ] +} + +resource "google_apigee_organization" "org" { + analytics_region = "us-central1" + display_name = "apigee-org" + description = "Terraform-provisioned Apigee Org without VPC Peering." + project_id = data.google_client_config.current.project + disable_vpc_peering = true + runtime_database_encryption_key_name = google_kms_crypto_key.apigee_key.id + + depends_on = [ + google_kms_crypto_key_iam_binding.apigee_sa_keyuser, + ] +} diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.erb b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.erb new file mode 100644 index 000000000000..e1857349148b --- /dev/null +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.erb @@ -0,0 +1,89 @@ +resource "google_project" "project" { + provider = google-beta + + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" + billing_account = "<%= ctx[:test_env_vars]['billing_account'] %>" +} + +resource "google_project_service" "apigee" { + provider = google-beta + + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "compute" { + provider = google-beta + + project = google_project.project.project_id + service = "compute.googleapis.com" +} + +resource "google_project_service" "kms" { + provider = google-beta + + project = google_project.project.project_id + service = "cloudkms.googleapis.com" +} + +resource "google_kms_key_ring" "apigee_keyring" { + provider = google-beta + + name = "apigee-keyring" + location = "us-central1" + project = google_project.project.project_id + depends_on = [google_project_service.kms] +} + +resource "google_kms_crypto_key" "apigee_key" { + provider = google-beta + + name = "apigee-key" + key_ring = google_kms_key_ring.apigee_keyring.id +} + +resource "google_project_service_identity" "apigee_sa" { + provider = google-beta + + project = google_project.project.project_id + service = google_project_service.apigee.service +} + +resource "google_kms_crypto_key_iam_binding" "apigee_sa_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.apigee_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:${google_project_service_identity.apigee_sa.email}", + ] +} + +resource "google_apigee_organization" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + display_name = "apigee-org" + description = "Terraform-provisioned Apigee Org without VPC Peering." + analytics_region = "us-central1" + project_id = google_project.project.project_id + disable_vpc_peering = true + billing_type = "EVALUATION" + runtime_database_encryption_key_name = google_kms_crypto_key.apigee_key.id + properties { + property { + name = "features.mart.connect.enabled" + value = "true" + } + property { + name = "features.hybrid.enabled" + value = "true" + } + } + + depends_on = [ + google_kms_crypto_key_iam_binding.apigee_sa_keyuser, + ] +} diff --git a/mmv1/templates/terraform/examples/database_migration_service_connection_profile_alloydb.tf.erb b/mmv1/templates/terraform/examples/database_migration_service_connection_profile_alloydb.tf.erb index 51421f2466c3..96384e6e4b58 100644 --- a/mmv1/templates/terraform/examples/database_migration_service_connection_profile_alloydb.tf.erb +++ b/mmv1/templates/terraform/examples/database_migration_service_connection_profile_alloydb.tf.erb @@ -11,16 +11,12 @@ resource "google_compute_global_address" "private_ip_alloc" { purpose = "VPC_PEERING" prefix_length = 16 network = google_compute_network.default.id - - depends_on = [google_compute_network.default] } resource "google_service_networking_connection" "vpc_connection" { network = google_compute_network.default.id service = "servicenetworking.googleapis.com" reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name] - - depends_on = [google_compute_global_address.private_ip_alloc] } @@ -38,7 +34,7 @@ resource "google_database_migration_service_connection_profile" "<%= ctx[:primar user = "alloyuser%{random_suffix}" password = "alloypass%{random_suffix}" } - vpc_network = "projects/${data.google_project.project.number}/global/networks/${google_compute_network.default.name}" + vpc_network = google_compute_network.default.id labels = { alloyfoo = "alloybar" } diff --git a/mmv1/templates/terraform/examples/dataplex_task_basic.tf.erb b/mmv1/templates/terraform/examples/dataplex_task_basic.tf.erb new file mode 100644 index 000000000000..c105741576c1 --- /dev/null +++ b/mmv1/templates/terraform/examples/dataplex_task_basic.tf.erb @@ -0,0 +1,46 @@ +data "google_project" "project" { + +} + +resource "google_dataplex_lake" "<%= ctx[:primary_resource_id] %>" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "<%= ctx[:test_env_vars]['project_name'] %>" +} + + +resource "google_dataplex_task" "<%= ctx[:primary_resource_id] %>" { + + task_id = "tf-test-task%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.<%= ctx[:primary_resource_id] %>.name + + description = "Test Task Basic" + + display_name = "task-basic" + + labels = { "count": "3" } + + trigger_spec { + type = "RECURRING" + disabled = false + max_retries = 3 + start_time = "2023-10-02T15:01:23Z" + schedule = "1 * * * *" + } + + execution_spec { + service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" + project = "<%= ctx[:test_env_vars]['project_name'] %>" + max_job_execution_lifetime = "100s" + kms_key = "234jn2kjn42k3n423" + } + + spark { + python_script_file = "gs://dataproc-examples/pyspark/hello-world/hello-world.py" + + } + + project = "<%= ctx[:test_env_vars]['project_name'] %>" + +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/dataplex_task_notebook.tf.erb b/mmv1/templates/terraform/examples/dataplex_task_notebook.tf.erb new file mode 100644 index 000000000000..cbf395520186 --- /dev/null +++ b/mmv1/templates/terraform/examples/dataplex_task_notebook.tf.erb @@ -0,0 +1,60 @@ +# VPC network +resource "google_compute_network" "default" { + name = "tf-test-workstation-cluster%{random_suffix}" + auto_create_subnetworks = true +} + + +data "google_project" "project" { + +} + +resource "google_dataplex_lake" "<%= ctx[:primary_resource_id] %>" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "<%= ctx[:test_env_vars]['project_name'] %>" +} + + +resource "google_dataplex_task" "<%= ctx[:primary_resource_id] %>" { + + task_id = "tf-test-task%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.<%= ctx[:primary_resource_id] %>.name + trigger_spec { + type = "RECURRING" + schedule = "1 * * * *" + } + + execution_spec { + service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" + args = { + TASK_ARGS = "--output_location,gs://spark-job-jars-anrajitha/task-result, --output_format, json" + } + } + notebook { + notebook = "gs://terraform-test/test-notebook.ipynb" + infrastructure_spec { + batch { + executors_count = 2 + max_executors_count = 100 + } + container_image { + image = "test-image" + java_jars = ["test-java-jars.jar"] + python_packages = ["gs://bucket-name/my/path/to/lib.tar.gz"] + properties = { "name": "wrench", "mass": "1.3kg", "count": "3" } + } + vpc_network { + network_tags = ["test-network-tag"] + network = google_compute_network.default.id + } + } + file_uris = ["gs://terraform-test/test.csv"] + archive_uris = ["gs://terraform-test/test.csv"] + + } + project = "<%= ctx[:test_env_vars]['project_name'] %>" + + +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/dataplex_task_spark.tf.erb b/mmv1/templates/terraform/examples/dataplex_task_spark.tf.erb new file mode 100644 index 000000000000..25363788007d --- /dev/null +++ b/mmv1/templates/terraform/examples/dataplex_task_spark.tf.erb @@ -0,0 +1,61 @@ +# VPC network +resource "google_compute_network" "default" { + name = "tf-test-workstation-cluster%{random_suffix}" + auto_create_subnetworks = true +} + +data "google_project" "project" { + +} + +resource "google_dataplex_lake" "<%= ctx[:primary_resource_id] %>" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "<%= ctx[:test_env_vars]['project_name'] %>" +} + + +resource "google_dataplex_task" "<%= ctx[:primary_resource_id] %>" { + + task_id = "tf-test-task%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.<%= ctx[:primary_resource_id] %>.name + trigger_spec { + type = "ON_DEMAND" + } + + description = "task-spark-terraform" + + execution_spec { + service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" + args = { + TASK_ARGS = "--output_location,gs://spark-job/task-result, --output_format, json" + } + + } + + spark { + infrastructure_spec { + batch { + executors_count = 2 + max_executors_count = 100 + } + container_image { + image = "test-image" + java_jars = ["test-java-jars.jar"] + python_packages = ["gs://bucket-name/my/path/to/lib.tar.gz"] + properties = { "name": "wrench", "mass": "1.3kg", "count": "3" } + } + vpc_network { + network_tags = ["test-network-tag"] + sub_network = google_compute_network.default.id + } + } + file_uris = ["gs://terrafrom-test/test.csv"] + archive_uris = ["gs://terraform-test/test.csv"] + sql_script = "show databases" + } + + project = "<%= ctx[:test_env_vars]['project_name'] %>" + +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/firestore_database.tf.erb b/mmv1/templates/terraform/examples/firestore_database.tf.erb index 11ee1300d2bb..659e57bbf1fa 100644 --- a/mmv1/templates/terraform/examples/firestore_database.tf.erb +++ b/mmv1/templates/terraform/examples/firestore_database.tf.erb @@ -1,7 +1,8 @@ resource "google_project" "project" { - project_id = "<%= ctx[:vars]['project_id'] %>" - name = "<%= ctx[:vars]['project_id'] %>" - org_id = "<%= ctx[:test_env_vars]['org_id'] %>" + project_id = "<%= ctx[:vars]['project_id'] %>" + name = "<%= ctx[:vars]['project_id'] %>" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" + billing_account = "<%= ctx[:test_env_vars]['billing_account'] %>" } resource "time_sleep" "wait_60_seconds" { @@ -20,7 +21,7 @@ resource "google_project_service" "firestore" { resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { project = google_project.project.project_id - name = "(default)" + name = "my-database" location_id = "nam5" type = "FIRESTORE_NATIVE" concurrency_mode = "OPTIMISTIC" diff --git a/mmv1/templates/terraform/examples/firestore_database_in_datastore_mode.tf.erb b/mmv1/templates/terraform/examples/firestore_database_in_datastore_mode.tf.erb new file mode 100644 index 000000000000..1f3b00af89b9 --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_database_in_datastore_mode.tf.erb @@ -0,0 +1,31 @@ +resource "google_project" "project" { + project_id = "<%= ctx[:vars]['project_id'] %>" + name = "<%= ctx[:vars]['project_id'] %>" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" + billing_account = "<%= ctx[:test_env_vars]['billing_account'] %>" +} + +resource "time_sleep" "wait_60_seconds" { + depends_on = [google_project.project] + create_duration = "60s" +} + +resource "google_project_service" "firestore" { + project = google_project.project.project_id + service = "firestore.googleapis.com" + + # Needed for CI tests for permissions to propagate, should not be needed for actual usage + depends_on = [time_sleep.wait_60_seconds] +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + project = google_project.project.project_id + name = "datastore-mode-database" + location_id = "nam5" + type = "DATASTORE_MODE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + + depends_on = [google_project_service.firestore] +} + diff --git a/mmv1/templates/terraform/examples/firestore_database_datastore_mode.tf.erb b/mmv1/templates/terraform/examples/firestore_default_database.tf.erb similarity index 86% rename from mmv1/templates/terraform/examples/firestore_database_datastore_mode.tf.erb rename to mmv1/templates/terraform/examples/firestore_default_database.tf.erb index 72bd758da073..36bc28e2c752 100644 --- a/mmv1/templates/terraform/examples/firestore_database_datastore_mode.tf.erb +++ b/mmv1/templates/terraform/examples/firestore_default_database.tf.erb @@ -13,18 +13,15 @@ resource "time_sleep" "wait_60_seconds" { resource "google_project_service" "firestore" { project = google_project.project.project_id service = "firestore.googleapis.com" - # Needed for CI tests for permissions to propagate, should not be needed for actual usage depends_on = [time_sleep.wait_60_seconds] } resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { - project = google_project.project.project_id - - name = "(default)" - + project = google_project.project.project_id + name = "(default)" location_id = "nam5" - type = "DATASTORE_MODE" + type = "FIRESTORE_NATIVE" depends_on = [google_project_service.firestore] } diff --git a/mmv1/templates/terraform/examples/firestore_default_database_in_datastore_mode.tf.erb b/mmv1/templates/terraform/examples/firestore_default_database_in_datastore_mode.tf.erb new file mode 100644 index 000000000000..afdd7aa4146e --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_default_database_in_datastore_mode.tf.erb @@ -0,0 +1,28 @@ +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" +} + +resource "time_sleep" "wait_60_seconds" { + depends_on = [google_project.project] + create_duration = "60s" +} + +resource "google_project_service" "firestore" { + project = google_project.project.project_id + service = "firestore.googleapis.com" + # Needed for CI tests for permissions to propagate, should not be needed for actual usage + depends_on = [time_sleep.wait_60_seconds] +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + project = google_project.project.project_id + + name = "(default)" + + location_id = "nam5" + type = "DATASTORE_MODE" + + depends_on = [google_project_service.firestore] +} diff --git a/mmv1/templates/terraform/examples/healthcare_fhir_store_basic.tf.erb b/mmv1/templates/terraform/examples/healthcare_fhir_store_basic.tf.erb index 1ff31c2fce66..9ac21971ab8c 100644 --- a/mmv1/templates/terraform/examples/healthcare_fhir_store_basic.tf.erb +++ b/mmv1/templates/terraform/examples/healthcare_fhir_store_basic.tf.erb @@ -2,6 +2,7 @@ resource "google_healthcare_fhir_store" "default" { name = "<%= ctx[:vars]['fhir_store_name'] %>" dataset = google_healthcare_dataset.dataset.id version = "R4" + complex_data_type_reference_parsing = "DISABLED" enable_update_create = false disable_referential_integrity = false diff --git a/mmv1/templates/terraform/examples/looker_instance_basic.tf.erb b/mmv1/templates/terraform/examples/looker_instance_basic.tf.erb new file mode 100644 index 000000000000..6c1591d53284 --- /dev/null +++ b/mmv1/templates/terraform/examples/looker_instance_basic.tf.erb @@ -0,0 +1,9 @@ +resource "google_looker_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]["instance_name"] %>" + platform_edition = "LOOKER_CORE_STANDARD" + region = "us-central1" + oauth_config { + client_id = "<%= ctx[:vars]["client_id"] %>" + client_secret = "<%= ctx[:vars]["client_secret"] %>" + } +} diff --git a/mmv1/templates/terraform/examples/looker_instance_enterprise_full.tf.erb b/mmv1/templates/terraform/examples/looker_instance_enterprise_full.tf.erb new file mode 100644 index 000000000000..1a0a8910f084 --- /dev/null +++ b/mmv1/templates/terraform/examples/looker_instance_enterprise_full.tf.erb @@ -0,0 +1,76 @@ +resource "google_looker_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]["instance_name"] %>" + platform_edition = "LOOKER_CORE_ENTERPRISE_ANNUAL" + region = "us-central1" + private_ip_enabled = true + public_ip_enabled = false + reserved_range = "${google_compute_global_address.looker_range.name}" + consumer_network = google_compute_network.looker_network.id + admin_settings { + allowed_email_domains = ["google.com"] + } + encryption_config { + kms_key_name = "<%= ctx[:vars]["kms_key_name"] %>" + } + maintenance_window { + day_of_week = "THURSDAY" + start_time { + hours = 22 + minutes = 0 + seconds = 0 + nanos = 0 + } + } + deny_maintenance_period { + start_date { + year = 2050 + month = 1 + day = 1 + } + end_date { + year = 2050 + month = 2 + day = 1 + } + time { + hours = 10 + minutes = 0 + seconds = 0 + nanos = 0 + } + } + oauth_config { + client_id = "<%= ctx[:vars]["client_id"] %>" + client_secret = "<%= ctx[:vars]["client_secret"] %>" + } + depends_on = [ + google_service_networking_connection.looker_vpc_connection + ] +} + +resource "google_service_networking_connection" "looker_vpc_connection" { + network = google_compute_network.looker_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.looker_range.name] +} + +resource "google_compute_global_address" "looker_range" { + name = "<%= ctx[:vars]["address_name"] %>" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 20 + network = google_compute_network.looker_network.id +} + +data "google_project" "project" {} + +resource "google_compute_network" "looker_network" { + name = "<%= ctx[:vars]["network_name"] %>" + auto_create_subnetworks = false +} + +resource "google_kms_crypto_key_iam_member" "crypto_key" { + crypto_key_id = "<%= ctx[:vars]["kms_key_name"] %>" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-looker.iam.gserviceaccount.com" +} diff --git a/mmv1/templates/terraform/examples/looker_instance_full.tf.erb b/mmv1/templates/terraform/examples/looker_instance_full.tf.erb new file mode 100644 index 000000000000..8a403997d93b --- /dev/null +++ b/mmv1/templates/terraform/examples/looker_instance_full.tf.erb @@ -0,0 +1,46 @@ +resource "google_looker_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]["instance_name"] %>" + platform_edition = "LOOKER_CORE_STANDARD" + region = "us-central1" + public_ip_enabled = true + admin_settings { + allowed_email_domains = ["google.com"] + } + // User metadata config is only available when platform edition is LOOKER_CORE_STANDARD. + user_metadata { + additional_developer_user_count = 10 + additional_standard_user_count = 10 + additional_viewer_user_count = 10 + } + maintenance_window { + day_of_week = "THURSDAY" + start_time { + hours = 22 + minutes = 0 + seconds = 0 + nanos = 0 + } + } + deny_maintenance_period { + start_date { + year = 2050 + month = 1 + day = 1 + } + end_date { + year = 2050 + month = 2 + day = 1 + } + time { + hours = 10 + minutes = 0 + seconds = 0 + nanos = 0 + } + } + oauth_config { + client_id = "<%= ctx[:vars]["client_id"] %>" + client_secret = "<%= ctx[:vars]["client_secret"] %>" + } +} diff --git a/mmv1/templates/terraform/examples/monitoring_monitored_project_basic.tf.erb b/mmv1/templates/terraform/examples/monitoring_monitored_project_basic.tf.erb index 994d9b66d14b..ce32ef1a7978 100644 --- a/mmv1/templates/terraform/examples/monitoring_monitored_project_basic.tf.erb +++ b/mmv1/templates/terraform/examples/monitoring_monitored_project_basic.tf.erb @@ -1,10 +1,10 @@ resource "google_monitoring_monitored_project" "<%= ctx[:primary_resource_id] %>" { metrics_scope = "<%= ctx[:test_env_vars]['project_id'] %>" - name = google_project.basic.name + name = google_project.basic.project_id } resource "google_project" "basic" { project_id = "<%= ctx[:vars]['monitored_project'] %>" - name = "<%= ctx[:vars]['monitored_project'] %>" + name = "<%= ctx[:vars]['monitored_project'] %>-display" org_id = "<%= ctx[:test_env_vars]['org_id'] %>" } diff --git a/mmv1/templates/terraform/examples/monitoring_monitored_project_long_form.tf.erb b/mmv1/templates/terraform/examples/monitoring_monitored_project_long_form.tf.erb new file mode 100644 index 000000000000..877056db134a --- /dev/null +++ b/mmv1/templates/terraform/examples/monitoring_monitored_project_long_form.tf.erb @@ -0,0 +1,10 @@ +resource "google_monitoring_monitored_project" "<%= ctx[:primary_resource_id] %>" { + metrics_scope = "<%= ctx[:test_env_vars]['project_id'] %>" + name = "locations/global/metricsScopes/<%= ctx[:test_env_vars]['project_id'] %>/projects/${google_project.basic.project_id}" +} + +resource "google_project" "basic" { + project_id = "<%= ctx[:vars]['monitored_project'] %>" + name = "<%= ctx[:vars]['monitored_project'] %>-display" + org_id = "<%= ctx[:test_env_vars]['org_id'] %>" +} diff --git a/mmv1/templates/terraform/examples/vpc_access_connector.tf.erb b/mmv1/templates/terraform/examples/vpc_access_connector.tf.erb index 1a9e997c5400..2880838173ff 100644 --- a/mmv1/templates/terraform/examples/vpc_access_connector.tf.erb +++ b/mmv1/templates/terraform/examples/vpc_access_connector.tf.erb @@ -1,5 +1,7 @@ resource "google_vpc_access_connector" "connector" { name = "<%= ctx[:vars]['name'] %>" - ip_cidr_range = "10.8.0.0/28" + ip_cidr_range = "10.18.0.0/28" network = "default" + min_instances = 2 + max_instances = 3 } diff --git a/mmv1/templates/terraform/examples/vpc_access_connector_shared_vpc.tf.erb b/mmv1/templates/terraform/examples/vpc_access_connector_shared_vpc.tf.erb index aae7c260019c..6297505716af 100644 --- a/mmv1/templates/terraform/examples/vpc_access_connector_shared_vpc.tf.erb +++ b/mmv1/templates/terraform/examples/vpc_access_connector_shared_vpc.tf.erb @@ -4,6 +4,8 @@ resource "google_vpc_access_connector" "connector" { name = google_compute_subnetwork.custom_test.name } machine_type = "e2-standard-4" + min_instances = 2 + max_instances = 3 } resource "google_compute_subnetwork" "custom_test" { @@ -16,4 +18,4 @@ resource "google_compute_subnetwork" "custom_test" { resource "google_compute_network" "custom_test" { name = "<%= ctx[:vars]['name'] %>" auto_create_subnetworks = false -} \ No newline at end of file +} diff --git a/mmv1/templates/terraform/examples/workflow_basic.tf.erb b/mmv1/templates/terraform/examples/workflow_basic.tf.erb index 45caf517b988..3369b4985048 100644 --- a/mmv1/templates/terraform/examples/workflow_basic.tf.erb +++ b/mmv1/templates/terraform/examples/workflow_basic.tf.erb @@ -9,30 +9,31 @@ resource "google_workflows_workflow" "<%= ctx[:primary_resource_id] %>" { description = "Magic" service_account = google_service_account.test_account.id source_contents = <<-EOF - # This is a sample workflow, feel free to replace it with your source code + # This is a sample workflow. You can replace it with your source code. # # This workflow does the following: # - reads current time and date information from an external API and stores - # the response in CurrentDateTime variable + # the response in currentTime variable # - retrieves a list of Wikipedia articles related to the day of the week - # from CurrentDateTime + # from currentTime # - returns the list of articles as an output of the workflow - # FYI, In terraform you need to escape the $$ or it will cause errors. + # + # Note: In Terraform you need to escape the $$ or it will cause errors. - getCurrentTime: call: http.get args: - url: https://us-central1-workflowsample.cloudfunctions.net/datetime - result: CurrentDateTime + url: https://timeapi.io/api/Time/current/zone?timeZone=Europe/Amsterdam + result: currentTime - readWikipedia: call: http.get args: url: https://en.wikipedia.org/w/api.php query: action: opensearch - search: $${CurrentDateTime.body.dayOfTheWeek} - result: WikiResult + search: $${currentTime.body.dayOfWeek} + result: wikiResult - returnOutput: - return: $${WikiResult.body[1]} + return: $${wikiResult.body[1]} EOF } diff --git a/mmv1/templates/terraform/post_create/compute_region_backend_service_security_policy.go.erb b/mmv1/templates/terraform/post_create/compute_region_backend_service_security_policy.go.erb new file mode 100644 index 000000000000..b80146f6077f --- /dev/null +++ b/mmv1/templates/terraform/post_create/compute_region_backend_service_security_policy.go.erb @@ -0,0 +1,39 @@ +<% unless version == 'ga' -%> +// security_policy isn't set by Create +if v, ok := d.GetOkExists("security_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, securityPolicyProp)) { + err = resourceComputeRegionBackendServiceRead(d, meta) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + securityPolicyProp, err := expandComputeRegionBackendServiceSecurityPolicy(v, d, config) + if err != nil { + return err + } + obj["security_policy"] = securityPolicyProp + + url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/backendServices/{{name}}/setSecurityPolicy") + if err != nil { + return err + } + + res, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: project, + RawURL: url, + UserAgent: userAgent, + Body: obj, + }) + + if err != nil { + return fmt.Errorf("Error adding SecurityPolicy to RegionBackendService %q: %s", d.Id(), err) + } + + err = ComputeOperationWaitTime(config, res, project, "Updating RegionBackendService SecurityPolicy", userAgent, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } +} +<% end -%> diff --git a/mmv1/templates/terraform/pre_read/monitoring_monitored_project.go.erb b/mmv1/templates/terraform/pre_read/monitoring_monitored_project.go.erb new file mode 100644 index 000000000000..0c73fb8b4eea --- /dev/null +++ b/mmv1/templates/terraform/pre_read/monitoring_monitored_project.go.erb @@ -0,0 +1,24 @@ +<%- # the license inside this block applies to this file + # Copyright 2023 Google Inc. + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. +-%> +name := d.Get("name").(string) +name = tpgresource.GetResourceNameFromSelfLink(name) +d.Set("name", name) +metricsScope := d.Get("metrics_scope").(string) +metricsScope = tpgresource.GetResourceNameFromSelfLink(metricsScope) +d.Set("metrics_scope", metricsScope) +url, err = tpgresource.ReplaceVars(d, config, "{{MonitoringBasePath}}v1/locations/global/metricsScopes/{{metrics_scope}}") +if err != nil { + return err +} diff --git a/mmv1/templates/terraform/resource_definition/connector.erb b/mmv1/templates/terraform/resource_definition/connector.erb new file mode 100644 index 000000000000..0452a6153fc5 --- /dev/null +++ b/mmv1/templates/terraform/resource_definition/connector.erb @@ -0,0 +1,3 @@ +CustomizeDiff: customdiff.All( + customdiff.ForceNewIfChange("min_instances", AreInstancesReduced), + customdiff.ForceNewIfChange("max_instances", AreInstancesReduced)), diff --git a/mmv1/templates/terraform/state_migrations/monitoring_monitored_project.go.erb b/mmv1/templates/terraform/state_migrations/monitoring_monitored_project.go.erb new file mode 100644 index 000000000000..9dc51b7fd2f7 --- /dev/null +++ b/mmv1/templates/terraform/state_migrations/monitoring_monitored_project.go.erb @@ -0,0 +1,35 @@ +func resourceMonitoringMonitoredProjectResourceV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metrics_scope": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareResourceNames, + Description: `Required. The resource name of the existing Metrics Scope that will monitor this project. Example: locations/global/metricsScopes/{SCOPING_PROJECT_ID_OR_NUMBER}`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareResourceNames, + Description: `Immutable. The resource name of the 'MonitoredProject'. On input, the resource name includes the scoping project ID and monitored project ID. On output, it contains the equivalent project numbers. Example: 'locations/global/metricsScopes/{SCOPING_PROJECT_ID_OR_NUMBER}/projects/{MONITORED_PROJECT_ID_OR_NUMBER}'`, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `Output only. The time when this 'MonitoredProject' was created.`, + }, + }, + UseJSONNumber: true, + } +} + +func ResourceMonitoringMonitoredProjectUpgradeV0(_ context.Context, rawState map[string]any, meta any) (map[string]any, error) { + log.Printf("[DEBUG] Attributes before migration: %#v", rawState) + + rawState["id"] = strings.TrimPrefix(rawState["id"].(string), "v1/") + + log.Printf("[DEBUG] Attributes after migration: %#v", rawState) + return rawState, nil +} diff --git a/mmv1/third_party/terraform/.teamcity/components/build_config_package.kt b/mmv1/third_party/terraform/.teamcity/components/build_config_package.kt index 5214736b21be..d6136cb22dc4 100644 --- a/mmv1/third_party/terraform/.teamcity/components/build_config_package.kt +++ b/mmv1/third_party/terraform/.teamcity/components/build_config_package.kt @@ -1,13 +1,17 @@ // this file is copied from mmv1, any changes made here will be overwritten import jetbrains.buildServer.configs.kotlin.* +import jetbrains.buildServer.configs.kotlin.AbsoluteId -class packageDetails(name: String, displayName: String, environment: String) { +class packageDetails(name: String, displayName: String, environment: String, branchRef: String) { val packageName = name val displayName = displayName val environment = environment + val branchRef = branchRef - fun buildConfiguration(providerName : String, path : String, nightlyTestsEnabled: Boolean, startHour: Int, parallelism: Int, daysOfWeek: String, daysOfMonth: String) : BuildType { + // buildConfiguration returns a BuildType for a service package + // For BuildType docs, see https://teamcity.jetbrains.com/app/dsl-documentation/root/build-type/index.html + fun buildConfiguration(providerName : String, path : String, manualVcsRoot: AbsoluteId, nightlyTestsEnabled: Boolean, startHour: Int, parallelism: Int, daysOfWeek: String, daysOfMonth: String) : BuildType { return BuildType { // TC needs a consistent ID for dynamically generated packages id(uniqueID(providerName)) @@ -15,7 +19,7 @@ class packageDetails(name: String, displayName: String, environment: String) { name = "%s - Acceptance Tests".format(displayName) vcs { - root(providerRepository) + root(rootId = manualVcsRoot) cleanCheckout = true } @@ -49,12 +53,18 @@ class packageDetails(name: String, displayName: String, environment: String) { } triggers { - RunNightly(nightlyTestsEnabled, startHour, daysOfWeek, daysOfMonth) + RunNightly(nightlyTestsEnabled, startHour, daysOfWeek, daysOfMonth, branchRef) } } } fun uniqueID(provider : String) : String { - return "%s_SERVICE_%s_%s".format(provider.replace("-", "").toUpperCase(), environment.toUpperCase(), packageName.toUpperCase()) + // Replacing chars can be necessary, due to limitations on IDs + // "ID should start with a latin letter and contain only latin letters, digits and underscores (at most 225 characters)." + var pv = provider.replace("-", "").toUpperCase() + var env = environment.toUpperCase().replace("-", "").replace(".", "").toUpperCase() + var pkg = packageName.toUpperCase() + + return "%s_SERVICE_%s_%s".format(pv, env, pkg) } } diff --git a/mmv1/third_party/terraform/.teamcity/components/build_google.kt b/mmv1/third_party/terraform/.teamcity/components/build_google.kt index 4baaddfc5225..d0209eb36cdd 100644 --- a/mmv1/third_party/terraform/.teamcity/components/build_google.kt +++ b/mmv1/third_party/terraform/.teamcity/components/build_google.kt @@ -19,6 +19,9 @@ class ClientConfiguration(var custId: String, val identityUser : String ) { } +// ParametrizedWithType.ConfigureGoogleSpecificTestParameters allows build configs to be created +// with the environment variables needed to configure the provider and/or configure test code. +// Extension of ParametrizedWithType. For docs, see https://teamcity.jetbrains.com/app/dsl-documentation/root/parametrized-with-type/index.html fun ParametrizedWithType.ConfigureGoogleSpecificTestParameters(config: ClientConfiguration) { hiddenPasswordVariable("env.GOOGLE_CUST_ID", config.custId, "The ID of the Google Identity Customer") hiddenPasswordVariable("env.GOOGLE_ORG", config.org, "The Google Organization Id") diff --git a/mmv1/third_party/terraform/.teamcity/components/generated/build_components.erb b/mmv1/third_party/terraform/.teamcity/components/generated/build_components.erb index 2539ba3970e3..5e8b2e035109 100644 --- a/mmv1/third_party/terraform/.teamcity/components/generated/build_components.erb +++ b/mmv1/third_party/terraform/.teamcity/components/generated/build_components.erb @@ -13,6 +13,15 @@ import jetbrains.buildServer.configs.kotlin.triggers.schedule // // Until that changes, we'll continue to use `teamcity-go-test` to run // each test individually + +// NOTE: this file includes Extensions of Kotlin DSL classes +// See +// - BuildFeatures https://teamcity.jetbrains.com/app/dsl-documentation/root/build-features/index.html +// - BuildSteps https://teamcity.jetbrains.com/app/dsl-documentation/root/build-steps/index.html +// - ParametrizedWithType https://teamcity.jetbrains.com/app/dsl-documentation/root/parametrized-with-type/index.html +// - Triggers https://teamcity.jetbrains.com/app/dsl-documentation/root/triggers/index.html + + const val useTeamCityGoTest = false fun BuildFeatures.Golang() { @@ -121,10 +130,12 @@ fun ParametrizedWithType.hiddenPasswordVariable(name: String, value: String, des password(name, value, "", description, ParameterDisplay.HIDDEN) } -fun Triggers.RunNightly(nightlyTestsEnabled: Boolean, startHour: Int, daysOfWeek: String, daysOfMonth: String) { +fun Triggers.RunNightly(nightlyTestsEnabled: Boolean, startHour: Int, daysOfWeek: String, daysOfMonth: String, branchRef: String) { + val filter = "+:" + branchRef // e.g. "+:refs/heads/main" + schedule{ enabled = nightlyTestsEnabled - branchFilter = "+:refs/heads/main" + branchFilter = filter schedulingPolicy = cron { hours = startHour.toString() diff --git a/mmv1/third_party/terraform/.teamcity/components/generated/project.erb b/mmv1/third_party/terraform/.teamcity/components/generated/project.erb index a1eb8701e37e..94997bbffcd5 100644 --- a/mmv1/third_party/terraform/.teamcity/components/generated/project.erb +++ b/mmv1/third_party/terraform/.teamcity/components/generated/project.erb @@ -3,32 +3,37 @@ import jetbrains.buildServer.configs.kotlin.BuildType import jetbrains.buildServer.configs.kotlin.Project +import jetbrains.buildServer.configs.kotlin.AbsoluteId const val providerName = "google<%= "-" + version unless version == 'ga' -%>" -fun Google<%= version.capitalize unless version == 'ga' -%>(environment: String, configuration : ClientConfiguration) : Project { +// Google<%= version.capitalize unless version == 'ga' -%> returns an instance of Project, +// which has multiple build configurations defined within it. +// See https://teamcity.jetbrains.com/app/dsl-documentation/root/project/index.html +fun Google<%= version.capitalize unless version == 'ga' -%>(environment: String, manualVcsRoot: AbsoluteId, branchRef: String, configuration: ClientConfiguration) : Project { return Project{ - vcsRoot(providerRepository) - var buildConfigs = buildConfigurationsForPackages(packages, providerName, "google<%= "-" + version unless version == 'ga' -%>", environment, configuration) + var buildConfigs = buildConfigurationsForPackages(packages, providerName, "google<%= "-" + version unless version == 'ga' -%>", environment, manualVcsRoot, branchRef, configuration) buildConfigs.forEach { buildConfiguration -> buildType(buildConfiguration) } } } -fun buildConfigurationsForPackages(packages: Map, providerName : String, path : String, environment: String, config : ClientConfiguration): List { +fun buildConfigurationsForPackages(packages: Map, providerName : String, path : String, environment: String, manualVcsRoot: AbsoluteId, branchRef: String, config: ClientConfiguration): List { var list = ArrayList() packages.forEach { (packageName, displayName) -> if (packageName == "services") { - var serviceList = buildConfigurationsForPackages(services, providerName, path+"/"+packageName, environment, config) + // `services` is a folder containing packages, not a package itself; call buildConfigurationsForPackages to iterate through directories found within `services` + var serviceList = buildConfigurationsForPackages(services, providerName, path+"/"+packageName, environment, manualVcsRoot, branchRef, config) list.addAll(serviceList) } else { - var defaultTestConfig = testConfiguration() + // other folders assumed to be packages + var testConfig = testConfiguration(environment) - var pkg = packageDetails(packageName, displayName, environment) - var buildConfig = pkg.buildConfiguration(providerName, path, true, defaultTestConfig.startHour, defaultTestConfig.parallelism, defaultTestConfig.daysOfWeek, defaultTestConfig.daysOfMonth) + var pkg = packageDetails(packageName, displayName, environment, branchRef) + var buildConfig = pkg.buildConfiguration(providerName, path, manualVcsRoot, true, testConfig.startHour, testConfig.parallelism, testConfig.daysOfWeek, testConfig.daysOfMonth) buildConfig.params.ConfigureGoogleSpecificTestParameters(config) @@ -39,9 +44,27 @@ fun buildConfigurationsForPackages(packages: Map, providerName : return list } -class testConfiguration(parallelism: Int = defaultParallelism, startHour: Int = defaultStartHour, daysOfWeek: String = defaultDaysOfWeek, daysOfMonth: String = defaultDaysOfMonth) { +class testConfiguration(environment: String, parallelism: Int = defaultParallelism, startHour: Int = defaultStartHour, daysOfWeek: String = defaultDaysOfWeek, daysOfMonth: String = defaultDaysOfMonth) { + + // Default values are present if init doesn't change them var parallelism = parallelism var startHour = startHour var daysOfWeek = daysOfWeek var daysOfMonth = daysOfMonth + + init { + // If the environment parameter is set to the value of MAJOR_RELEASE_TESTING, + // change the days of week to the day for v5.0.0 feature branch testing + if (environment == MAJOR_RELEASE_TESTING) { + this.parallelism = parallelism + this.startHour = startHour +<% if version == 'ga' -%> + this.daysOfWeek = "4" // Thursday for GA +<% elsif version == 'beta' -%> + this.daysOfWeek = "5" // Friday for Beta +<% end -%> + this.daysOfMonth = daysOfMonth + } + } + } \ No newline at end of file diff --git a/mmv1/third_party/terraform/.teamcity/components/generated/settings.erb b/mmv1/third_party/terraform/.teamcity/components/generated/settings.erb new file mode 100644 index 000000000000..5ac811536355 --- /dev/null +++ b/mmv1/third_party/terraform/.teamcity/components/generated/settings.erb @@ -0,0 +1,25 @@ +<% autogen_exception -%> +// this file is auto-generated with mmv1, any changes made here will be overwritten + +// specifies the default hour (UTC) at which tests should be triggered, if enabled +var defaultStartHour = 4 + +// specifies the default level of parallelism per-service-package +var defaultParallelism = 12 + +// specifies the default version of Terraform Core which should be used for testing +var defaultTerraformCoreVersion = "1.2.5" + +// This represents a cron view of days of the week +<% if version == 'ga' -%> +const val defaultDaysOfWeek = "1-3,5-7" // All nights except Thursday for GA; feature branch testing happens on Thursdays +<% elsif version == 'beta' -%> +const val defaultDaysOfWeek = "1-4,6,7" // All nights except Friday for Beta; feature branch testing happens on Fridays +<% end -%> + +// Cron value for any day of month +const val defaultDaysOfMonth = "*" + +// Values that `environment` parameter is checked against, +// when deciding to change how TeamCity objects are configured +const val MAJOR_RELEASE_TESTING = "major-release-5.0.0-testing" \ No newline at end of file diff --git a/mmv1/third_party/terraform/.teamcity/components/generated/vcs_root.erb b/mmv1/third_party/terraform/.teamcity/components/generated/vcs_root.erb deleted file mode 100644 index ff485939eb59..000000000000 --- a/mmv1/third_party/terraform/.teamcity/components/generated/vcs_root.erb +++ /dev/null @@ -1,14 +0,0 @@ -<% autogen_exception -%> -// this file is auto-generated with mmv1, any changes made here will be overwritten - -import jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot - -object providerRepository : GitVcsRoot({ - name = "terraform-provider-google<%= "-" + version unless version == 'ga' -%>" - url = "https://github.com/hashicorp/terraform-provider-google<%= "-" + version unless version == 'ga' -%>.git" - agentCleanPolicy = AgentCleanPolicy.ON_BRANCH_CHANGE - agentCleanFilesPolicy = AgentCleanFilesPolicy.ALL_UNTRACKED - branchSpec = "+:*" - branch = "refs/heads/main" - authMethod = anonymous() -}) diff --git a/mmv1/third_party/terraform/.teamcity/components/packages.kt b/mmv1/third_party/terraform/.teamcity/components/packages.kt index c1355e359852..415e33c47bc7 100644 --- a/mmv1/third_party/terraform/.teamcity/components/packages.kt +++ b/mmv1/third_party/terraform/.teamcity/components/packages.kt @@ -2,6 +2,8 @@ var packages = mapOf( "acctest" to "AccTest", + "provider" to "SDK Provider", + "fwprovider" to "Framework Plugin Provider", "services" to "Services", "tpgdclresource" to "TPG DCL Resource", "tpgiamresource" to "TPG IAM Resource", diff --git a/mmv1/third_party/terraform/.teamcity/components/settings.kt b/mmv1/third_party/terraform/.teamcity/components/settings.kt deleted file mode 100644 index 44f98ded7b4d..000000000000 --- a/mmv1/third_party/terraform/.teamcity/components/settings.kt +++ /dev/null @@ -1,16 +0,0 @@ -// this file is copied from mmv1, any changes made here will be overwritten - -// specifies the default hour (UTC) at which tests should be triggered, if enabled -var defaultStartHour = 4 - -// specifies the default level of parallelism per-service-package -var defaultParallelism = 12 - -// specifies the default version of Terraform Core which should be used for testing -var defaultTerraformCoreVersion = "1.2.5" - -// This represents a cron view of days of the week, Monday - Friday. -const val defaultDaysOfWeek = "*" - -// Cron value for any day of month -const val defaultDaysOfMonth = "*" diff --git a/mmv1/third_party/terraform/.teamcity/generated/pom.xml.erb b/mmv1/third_party/terraform/.teamcity/generated/pom.xml.erb index 640a4a7f7530..d5c86d528953 100644 --- a/mmv1/third_party/terraform/.teamcity/generated/pom.xml.erb +++ b/mmv1/third_party/terraform/.teamcity/generated/pom.xml.erb @@ -96,7 +96,7 @@ kotlin target/generated-configs - public + default diff --git a/mmv1/third_party/terraform/.teamcity/generated/settings.kts.erb b/mmv1/third_party/terraform/.teamcity/generated/settings.kts.erb index 113c8a9b3a28..e3b810f86a41 100644 --- a/mmv1/third_party/terraform/.teamcity/generated/settings.kts.erb +++ b/mmv1/third_party/terraform/.teamcity/generated/settings.kts.erb @@ -8,6 +8,12 @@ import jetbrains.buildServer.configs.kotlin.* version = "2023.05" +// The code below pulls context parameters from the TeamCity project. +// Context parameters aren't stored in VCS, and are managed manually. +// Due to this, the code needs to explicitly pull in values via the DSL and pass the values into other code. +// For DslContext docs, see https://teamcity.jetbrains.com/app/dsl-documentation/root/dsl-context/index.html + +// Values of these parameters are used to set ENVs needed for acceptance tests within the build configurations. var custId = DslContext.getParameter("custId", "") var org = DslContext.getParameter("org", "") var org2 = DslContext.getParameter("org2", "") @@ -21,10 +27,19 @@ var region = DslContext.getParameter("region", "") var serviceAccount = DslContext.getParameter("serviceAccount", "") var zone = DslContext.getParameter("zone", "") var credentials = DslContext.getParameter("credentials", "") -var environment = DslContext.getParameter("environment", "public") var firestoreProject = DslContext.getParameter("firestoreProject", "") var identityUser = DslContext.getParameter("identityUser", "") +// Get details of the VCS Root that's manually made when VCS is first +// connected to the Project in TeamCity +var manualVcsRoot = DslContext.settingsRootId + +// Values of these parameters change configuration code behaviour. +var environment = DslContext.getParameter("environment", "default") +var branchRef = DslContext.getParameter("branch", "refs/heads/main") + var clientConfig = ClientConfiguration(custId, org, org2, billingAccount, billingAccount2, masterBillingAccount, credentials, project, orgDomain, projectNumber, region, serviceAccount, zone, firestoreProject, identityUser) -project(Google<%= version.capitalize unless version == 'ga' -%>(environment, clientConfig)) +// This is the entry point of the code in .teamcity/ +// See https://teamcity.jetbrains.com/app/dsl-documentation/root/project.html +project(Google<%= version.capitalize unless version == 'ga' -%>(environment, manualVcsRoot, branchRef, clientConfig)) diff --git a/mmv1/third_party/terraform/.teamcity/tests/generated/configuration.erb b/mmv1/third_party/terraform/.teamcity/tests/generated/configuration.erb index 75385974852e..13f45f0fb640 100644 --- a/mmv1/third_party/terraform/.teamcity/tests/generated/configuration.erb +++ b/mmv1/third_party/terraform/.teamcity/tests/generated/configuration.erb @@ -12,7 +12,7 @@ import useTeamCityGoTest class ConfigurationTests { @Test fun buildShouldFailOnError() { - val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestConfiguration()) + val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestVcsRootId(), "refs/heads/main", TestConfiguration()) project.buildTypes.forEach { bt -> assertTrue("Build '${bt.id}' should fail on errors!", bt.failureConditions.errorMessage) } @@ -20,7 +20,7 @@ class ConfigurationTests { @Test fun buildShouldHaveGoTestFeature() { - val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestConfiguration()) + val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestVcsRootId(), "refs/heads/main",TestConfiguration()) project.buildTypes.forEach{ bt -> var exists = false bt.features.items.forEach { f -> @@ -37,7 +37,7 @@ class ConfigurationTests { @Test fun buildShouldHaveTrigger() { - val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestConfiguration()) + val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestVcsRootId(), "refs/heads/main", TestConfiguration()) var exists = false project.buildTypes.forEach{ bt -> bt.triggers.items.forEach { t -> diff --git a/mmv1/third_party/terraform/.teamcity/tests/generated/vcs_roots.erb b/mmv1/third_party/terraform/.teamcity/tests/generated/vcs_roots.erb index ac315f6209ba..9c8c01f5506d 100644 --- a/mmv1/third_party/terraform/.teamcity/tests/generated/vcs_roots.erb +++ b/mmv1/third_party/terraform/.teamcity/tests/generated/vcs_roots.erb @@ -11,7 +11,7 @@ import org.junit.Test class VcsTests { @Test fun buildsHaveCleanCheckOut() { - val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestConfiguration()) + val project = Google<%= version.capitalize unless version == 'ga' -%>("public", TestVcsRootId(), "refs/heads/main", TestConfiguration()) project.buildTypes.forEach { bt -> assertTrue("Build '${bt.id}' doesn't use clean checkout", bt.vcs.cleanCheckout) } diff --git a/mmv1/third_party/terraform/.teamcity/tests/helpers.kt b/mmv1/third_party/terraform/.teamcity/tests/helpers.kt index 390493a68d06..363a7a1b66cc 100644 --- a/mmv1/third_party/terraform/.teamcity/tests/helpers.kt +++ b/mmv1/third_party/terraform/.teamcity/tests/helpers.kt @@ -2,8 +2,14 @@ package tests +import jetbrains.buildServer.configs.kotlin.AbsoluteId + import ClientConfiguration fun TestConfiguration() : ClientConfiguration { return ClientConfiguration("custId", "org", "org2", "billingAccount", "billingAccount2", "masterBillingAccount", "credentials", "project", "orgDomain", "projectNumber", "region", "serviceAccount", "zone", "firestoreProject", "identityUser") +} + +fun TestVcsRootId() : AbsoluteId { + return AbsoluteId("TerraformProviderFoobar") } \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_sweeper.go.erb b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_sweeper.go.erb new file mode 100644 index 000000000000..f801542b1d17 --- /dev/null +++ b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_cluster_sweeper.go.erb @@ -0,0 +1,135 @@ +<% autogen_exception -%> +package alloydb + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("AlloydbCluster", testSweepAlloydbCluster) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepAlloydbCluster(region string) error { + resourceName := "AlloydbCluster" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + +<% unless version == 'ga' -%> + listTemplate := strings.Split("https://alloydb.googleapis.com/v1beta/projects/{{project}}/locations/{{location}}/clusters", "?")[0] +<% else -%> + listTemplate := strings.Split("https://alloydb.googleapis.com/v1/projects/{{project}}/locations/{{location}}/clusters", "?")[0] +<% end -%> + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["clusters"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + var name string + // Id detected in the delete URL, attempt to use id. + if obj["id"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["id"].(string)) + } else if obj["name"] != nil { + name = tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + } else { + log.Printf("[INFO][SWEEPER_LOG] %s resource name and id were nil", resourceName) + return nil + } + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + <% unless version == 'ga' -%> + deleteTemplate := "https://alloydb.googleapis.com/v1beta/projects/{{project}}/locations/{{location}}/clusters/{{cluster_id}}" + <% else -%> + deleteTemplate := "https://alloydb.googleapis.com/v1/projects/{{project}}/locations/{{location}}/clusters/{{cluster_id}}" + <% end -%> + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + "?force=true" + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table.go b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table.go index e8cac881fc55..dafd68aa86be 100644 --- a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table.go +++ b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table.go @@ -538,6 +538,45 @@ func ResourceBigQueryTable() *schema.Resource { }, }, }, + // jsonOptions: [Optional] Additional properties to set if sourceFormat is set to JSON. + "json_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: `Additional properties to set if sourceFormat is set to JSON."`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "encoding": { + Type: schema.TypeString, + Optional: true, + Default: "UTF-8", + ValidateFunc: validation.StringInSlice([]string{"UTF-8", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE"}, false), + Description: `The character encoding of the data. The supported values are UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, and UTF-32LE. The default value is UTF-8.`, + }, + }, + }, + }, + + "parquet_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: `Additional properties to set if sourceFormat is set to PARQUET."`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enum_as_string": { + Type: schema.TypeBool, + Optional: true, + Description: `Indicates whether to infer Parquet ENUM logical type as STRING instead of BYTES by default.`, + }, + "enable_list_inference": { + Type: schema.TypeBool, + Optional: true, + Description: `Indicates whether to use schema inference specifically for Parquet LIST logical type.`, + }, + }, + }, + }, // GoogleSheetsOptions: [Optional] Additional options if sourceFormat is set to GOOGLE_SHEETS. "google_sheets_options": { Type: schema.TypeList, @@ -1370,9 +1409,13 @@ func expandExternalDataConfiguration(cfg interface{}) (*bigquery.ExternalDataCon if v, ok := raw["compression"]; ok { edc.Compression = v.(string) } + if v, ok := raw["csv_options"]; ok { edc.CsvOptions = expandCsvOptions(v) } + if v, ok := raw["json_options"]; ok { + edc.JsonOptions = expandJsonOptions(v) + } if v, ok := raw["google_sheets_options"]; ok { edc.GoogleSheetsOptions = expandGoogleSheetsOptions(v) } @@ -1382,6 +1425,10 @@ func expandExternalDataConfiguration(cfg interface{}) (*bigquery.ExternalDataCon if v, ok := raw["avro_options"]; ok { edc.AvroOptions = expandAvroOptions(v) } + if v, ok := raw["parquet_options"]; ok { + edc.ParquetOptions = expandParquetOptions(v) + } + if v, ok := raw["ignore_unknown_values"]; ok { edc.IgnoreUnknownValues = v.(bool) } @@ -1441,6 +1488,14 @@ func flattenExternalDataConfiguration(edc *bigquery.ExternalDataConfiguration) ( result["avro_options"] = flattenAvroOptions(edc.AvroOptions) } + if edc.ParquetOptions != nil { + result["parquet_options"] = flattenParquetOptions(edc.ParquetOptions) + } + + if edc.JsonOptions != nil { + result["json_options"] = flattenJsonOptions(edc.JsonOptions) + } + if edc.IgnoreUnknownValues { result["ignore_unknown_values"] = edc.IgnoreUnknownValues } @@ -1638,6 +1693,64 @@ func flattenAvroOptions(opts *bigquery.AvroOptions) []map[string]interface{} { return []map[string]interface{}{result} } +func expandParquetOptions(configured interface{}) *bigquery.ParquetOptions { + if len(configured.([]interface{})) == 0 { + return nil + } + + raw := configured.([]interface{})[0].(map[string]interface{}) + opts := &bigquery.ParquetOptions{} + + if v, ok := raw["enum_as_string"]; ok { + opts.EnumAsString = v.(bool) + } + + if v, ok := raw["enable_list_inference"]; ok { + opts.EnableListInference = v.(bool) + } + + return opts +} + +func flattenParquetOptions(opts *bigquery.ParquetOptions) []map[string]interface{} { + result := map[string]interface{}{} + + if opts.EnumAsString { + result["enum_as_string"] = opts.EnumAsString + } + + if opts.EnableListInference { + result["enable_list_inference"] = opts.EnableListInference + } + + return []map[string]interface{}{result} +} + +func expandJsonOptions(configured interface{}) *bigquery.JsonOptions { + if len(configured.([]interface{})) == 0 { + return nil + } + + raw := configured.([]interface{})[0].(map[string]interface{}) + opts := &bigquery.JsonOptions{} + + if v, ok := raw["encoding"]; ok { + opts.Encoding = v.(string) + } + + return opts +} + +func flattenJsonOptions(opts *bigquery.JsonOptions) []map[string]interface{} { + result := map[string]interface{}{} + + if opts.Encoding != "" { + result["encoding"] = opts.Encoding + } + + return []map[string]interface{}{result} +} + func expandSchema(raw interface{}) (*bigquery.TableSchema, error) { var fields []*bigquery.TableFieldSchema diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance.go index 69fcb2ddcb4b..ecb97c65aa52 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance.go @@ -80,7 +80,7 @@ func ResourceBigtableInstance() *schema.Resource { // so mark as computed. Computed: true, ValidateFunc: validation.IntAtLeast(1), - Description: `The number of nodes in your Cloud Bigtable cluster. Required, with a minimum of 1 for each cluster in an instance.`, + Description: `The number of nodes in the cluster. If no value is set, Cloud Bigtable automatically allocates nodes based on your data footprint and optimized for 50% storage utilization.`, }, "storage_type": { Type: schema.TypeString, diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go index 64df024e5b49..cd5d4f334b70 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go @@ -97,7 +97,7 @@ func ResourceBigtableTable() *schema.Resource { Optional: true, Computed: true, ValidateFunc: verify.ValidateDuration(), - Description: `Duration to retain change stream data for the table. Set to 0 to disable.`, + Description: `Duration to retain change stream data for the table. Set to 0 to disable. Must be between 1 and 7 days.`, }, }, UseJSONNumber: true, diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb index 806db93b79e7..16074a3703bd 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb @@ -815,9 +815,9 @@ func ResourceComposerEnvironment() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, + ForceNew: false, AtLeastOneOf: composerConfigKeys, - ValidateFunc: validation.StringInSlice([]string{"HIGH_RESILIENCE"}, false), + ValidateFunc: validation.StringInSlice([]string{"STANDARD_RESILIENCE", "HIGH_RESILIENCE"}, false), Description: `Whether high resilience is enabled or not. This field is supported for Cloud Composer environments in versions composer-2.1.15-airflow-*.*.* and newer.`, }, "master_authorized_networks_config": { @@ -1176,7 +1176,7 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) } } - if d.HasChange("config.0.environment_size") { + if d.HasChange("config.0.environment_size") { patchObj := &composer.Environment{Config: &composer.EnvironmentConfig{}} if config != nil { patchObj.Config.EnvironmentSize = config.EnvironmentSize @@ -1186,6 +1186,20 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) return err } } + if d.HasChange("config.0.resilience_mode") { + patchObj := &composer.Environment{Config: &composer.EnvironmentConfig{}} + if config != nil { + if config.ResilienceMode == "STANDARD_RESILIENCE" { + patchObj.Config.ResilienceMode = "RESILIENCE_MODE_UNSPECIFIED" + } else { + patchObj.Config.ResilienceMode = config.ResilienceMode + } + } + err = resourceComposerEnvironmentPatchField("config.ResilienceMode", userAgent, patchObj, d, tfConfig) + if err != nil { + return err + } + } if d.HasChange("config.0.master_authorized_networks_config") { patchObj := &composer.Environment{Config: &composer.EnvironmentConfig{}} if config != nil { @@ -1320,7 +1334,11 @@ func flattenComposerEnvironmentConfig(envCfg *composer.EnvironmentConfig) interf transformed["workloads_config"] = flattenComposerEnvironmentConfigWorkloadsConfig(envCfg.WorkloadsConfig) transformed["recovery_config"] = flattenComposerEnvironmentConfigRecoveryConfig(envCfg.RecoveryConfig) transformed["environment_size"] = envCfg.EnvironmentSize - transformed["resilience_mode"] = envCfg.ResilienceMode + if envCfg.ResilienceMode == "RESILIENCE_MODE_UNSPECIFIED" || envCfg.ResilienceMode == "" { + transformed["resilience_mode"] = "STANDARD_RESILIENCE" + } else { + transformed["resilience_mode"] = envCfg.ResilienceMode + } transformed["master_authorized_networks_config"] = flattenComposerEnvironmentConfigMasterAuthorizedNetworksConfig(envCfg.MasterAuthorizedNetworksConfig) return []interface{}{transformed} } @@ -1682,7 +1700,12 @@ func expandComposerEnvironmentConfig(v interface{}, d *schema.ResourceData, conf if err != nil { return nil, err } - transformed.ResilienceMode = transformedResilienceMode + if transformedResilienceMode == "STANDARD_RESILIENCE" { + transformed.ResilienceMode = "RESILIENCE_MODE_UNSPECIFIED" + } else { + transformed.ResilienceMode = transformedResilienceMode + } + transformedMasterAuthorizedNetworksConfig, err := expandComposerEnvironmentConfigMasterAuthorizedNetworksConfig(original["master_authorized_networks_config"], d, config) if err != nil { diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_image.go.erb b/mmv1/third_party/terraform/services/compute/data_source_google_compute_image.go.erb index 5852144e5429..5fece43bc8e7 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_image.go.erb +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_image.go.erb @@ -5,6 +5,7 @@ import ( "fmt" "log" "strconv" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-google/google/tpgresource" @@ -114,6 +115,11 @@ func DataSourceGoogleComputeImage() *schema.Resource { Optional: true, ForceNew: true, }, + "most_recent": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, }, } } @@ -149,6 +155,19 @@ func dataSourceGoogleComputeImageRead(d *schema.ResourceData, meta interface{}) for _, im := range images.Items { image = im } + } else if mr, ok := d.GetOk("most_recent"); len(images.Items) >= 1 && ok && mr.(bool) { + most_recent := time.UnixMicro(0) + for _, im := range images.Items { + parsedTS, err := time.Parse(time.RFC3339, im.CreationTimestamp) + if err != nil { + return fmt.Errorf("error parsing creation timestamp: %w", err) + } + + if parsedTS.After(most_recent) { + most_recent = parsedTS + image = im + } + } } else { return fmt.Errorf("your filter has returned more than one image or no image. Please refine your filter to return exactly one image") } diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb index 1458c1fedada..775ab9e42d71 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb @@ -102,6 +102,14 @@ func forceNewIfNetworkIPNotUpdatableFunc(d tpgresource.TerraformResourceDiff) er return nil } +// User may specify AUTOMATIC using any case; the API will accept it and return an empty string. +func ComputeInstanceMinCpuPlatformEmptyOrAutomaticDiffSuppress(k, old, new string, d *schema.ResourceData) bool { + old = strings.ToLower(old) + new = strings.ToLower(new) + defaultVal := "automatic" + return (old == "" && new == defaultVal) || (new == "" && old == defaultVal) +} + func ResourceComputeInstance() *schema.Resource { return &schema.Resource{ Create: resourceComputeInstanceCreate, @@ -596,10 +604,11 @@ func ResourceComputeInstance() *schema.Resource { }, "min_cpu_platform": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: `The minimum CPU platform specified for the VM instance.`, + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `The minimum CPU platform specified for the VM instance.`, + DiffSuppressFunc: ComputeInstanceMinCpuPlatformEmptyOrAutomaticDiffSuppress, }, "project": { @@ -2020,40 +2029,34 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } - if d.HasChange("machine_type") { - mt, err := tpgresource.ParseMachineTypesFieldValue(d.Get("machine_type").(string), d, config) - if err != nil { - return err - } - req := &compute.InstancesSetMachineTypeRequest{ - MachineType: mt.RelativeLink(), + if d.HasChange("min_cpu_platform") { + minCpuPlatform := d.Get("min_cpu_platform") + req := &compute.InstancesSetMinCpuPlatformRequest{ + MinCpuPlatform: minCpuPlatform.(string), } - op, err := config.NewComputeClient(userAgent).Instances.SetMachineType(project, zone, instance.Name, req).Do() + op, err := config.NewComputeClient(userAgent).Instances.SetMinCpuPlatform(project, zone, instance.Name, req).Do() if err != nil { return err } - opErr := ComputeOperationWaitTime(config, op, project, "updating machinetype", userAgent, d.Timeout(schema.TimeoutUpdate)) + opErr := ComputeOperationWaitTime(config, op, project, "updating min cpu platform", userAgent, d.Timeout(schema.TimeoutUpdate)) if opErr != nil { return opErr } } - if d.HasChange("min_cpu_platform") { - minCpuPlatform, ok := d.GetOk("min_cpu_platform") - // Even though you don't have to set minCpuPlatform on create, you do have to set it to an - // actual value on update. "Automatic" is the default. This will be read back from the API as empty, - // so we don't need to worry about diffs. - if !ok { - minCpuPlatform = "Automatic" + if d.HasChange("machine_type") { + mt, err := tpgresource.ParseMachineTypesFieldValue(d.Get("machine_type").(string), d, config) + if err != nil { + return err } - req := &compute.InstancesSetMinCpuPlatformRequest{ - MinCpuPlatform: minCpuPlatform.(string), + req := &compute.InstancesSetMachineTypeRequest{ + MachineType: mt.RelativeLink(), } - op, err := config.NewComputeClient(userAgent).Instances.SetMinCpuPlatform(project, zone, instance.Name, req).Do() + op, err := config.NewComputeClient(userAgent).Instances.SetMachineType(project, zone, instance.Name, req).Do() if err != nil { return err } - opErr := ComputeOperationWaitTime(config, op, project, "updating min cpu platform", userAgent, d.Timeout(schema.TimeoutUpdate)) + opErr := ComputeOperationWaitTime(config, op, project, "updating machinetype", userAgent, d.Timeout(schema.TimeoutUpdate)) if opErr != nil { return opErr } diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb index efefc1f71fa0..c49c1b61c20a 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb @@ -5,6 +5,9 @@ import ( "context" "fmt" "log" +<% if version != 'ga' -%> + "strings" +<% end -%> "time" @@ -280,7 +283,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource { "enforce_on_key_configs": { Type: schema.TypeList, Description: `Enforce On Key Config of this security policy`, - ForceNew: true, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -772,7 +774,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ } } - + <% if version == 'ga' -%> if d.HasChange("rule") { o, n := d.GetChange("rule") oSet := o.(*schema.Set) @@ -788,12 +790,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ priority := int64(rule.(map[string]interface{})["priority"].(int)) nPriorities[priority] = true if !oPriorities[priority] { - <% if version == 'ga' -%> - client := config.NewComputeClient(userAgent) - <% else -%> client := config.NewComputeClient(userAgent) - <% end -%> - // If the rule is in new and its priority does not exist in old, then add it. op, err := client.SecurityPolicies.AddRule(project, sp, expandSecurityPolicyRule(rule)).Do() @@ -806,11 +803,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ return err } } else if !oSet.Contains(rule) { - <% if version == 'ga' -%> - client := config.NewComputeClient(userAgent) - <% else -%> client := config.NewComputeClient(userAgent) - <% end -%> // If the rule is in new, and its priority is in old, but its hash is different than the one in old, update it. op, err := client.SecurityPolicies.PatchRule(project, sp, expandSecurityPolicyRule(rule)).Priority(priority).Do() @@ -829,11 +822,109 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ for _, rule := range oSet.List() { priority := int64(rule.(map[string]interface{})["priority"].(int)) if !nPriorities[priority] { - <% if version == 'ga' -%> client := config.NewComputeClient(userAgent) - <% else -%> + + // If the rule's priority is in old but not new, remove it. + op, err := client.SecurityPolicies.RemoveRule(project, sp).Priority(priority).Do() + + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating SecurityPolicy %q: {{err}}", sp), err) + } + + err = ComputeOperationWaitTime(config, op, project, fmt.Sprintf("Updating SecurityPolicy %q", sp), userAgent, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + } + + <% else -%> + if d.HasChange("rule") { + o, n := d.GetChange("rule") + oSet := o.(*schema.Set) + nSet := n.(*schema.Set) + + oPriorities := map[int64]bool{} + nPriorities := map[int64]bool{} + oRules := make(map[int64]map[string]interface{}) + nRules := make(map[int64]map[string]interface{}) + + for _, rule := range oSet.List() { + oPriorities[int64(rule.(map[string]interface{})["priority"].(int))] = true + oRules[int64(rule.(map[string]interface{})["priority"].(int))] = rule.(map[string]interface{}) + } + + for _, rule := range nSet.List() { + nRules[int64(rule.(map[string]interface{})["priority"].(int))] = rule.(map[string]interface{}) + priority := int64(rule.(map[string]interface{})["priority"].(int)) + nPriorities[priority] = true + + if !oPriorities[priority] { + client := config.NewComputeClient(userAgent) + + // If the rule is in new and its priority does not exist in old, then add it. + op, err := client.SecurityPolicies.AddRule(project, sp, expandSecurityPolicyRule(rule)).Do() + + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating SecurityPolicy %q: {{err}}", sp), err) + } + + err = ComputeOperationWaitTime(config, op, project, fmt.Sprintf("Updating SecurityPolicy %q", sp), userAgent, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } else if !oSet.Contains(rule) { + + oMap := make(map[string]interface{}) + nMap := make(map[string]interface{}) + + updateMask := []string{} + + if oRules[priority]["rate_limit_options"] != nil { + for _, oValue := range oRules[priority]["rate_limit_options"].([]interface{}) { + oMap = oValue.(map[string]interface{}) + } + } + + if nRules[priority]["rate_limit_options"] != nil { + for _, nValue := range nRules[priority]["rate_limit_options"].([]interface{}) { + nMap = nValue.(map[string]interface{}) + } + } + + if fmt.Sprintf("%v", oMap["enforce_on_key"]) != fmt.Sprintf("%v", nMap["enforce_on_key"]) { + updateMask = append(updateMask, "rate_limit_options.enforce_on_key") + } + + if fmt.Sprintf("%v", oMap["enforce_on_key_configs"]) != fmt.Sprintf("%v", nMap["enforce_on_key_configs"]) { + updateMask = append(updateMask, "rate_limit_options.enforce_on_key_configs") + } + + if fmt.Sprintf("%v", oMap["enforce_on_key_name"]) != fmt.Sprintf("%v", nMap["enforce_on_key_name"]) { + updateMask = append(updateMask, "rate_limit_options.enforce_on_key_name") + } + + client := config.NewComputeClient(userAgent) + + // If the rule is in new, and its priority is in old, but its hash is different than the one in old, update it. + op, err := client.SecurityPolicies.PatchRule(project, sp, expandSecurityPolicyRule(rule)).Priority(priority).UpdateMask(strings.Join(updateMask, ",")).Do() + + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error updating SecurityPolicy %q: {{err}}", sp), err) + } + + err = ComputeOperationWaitTime(config, op, project, fmt.Sprintf("Updating SecurityPolicy %q", sp), userAgent, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + } + } + + for _, rule := range oSet.List() { + priority := int64(rule.(map[string]interface{})["priority"].(int)) + if !nPriorities[priority] { client := config.NewComputeClient(userAgent) - <% end -%> // If the rule's priority is in old but not new, remove it. op, err := client.SecurityPolicies.RemoveRule(project, sp).Priority(priority).Do() @@ -849,6 +940,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ } } } + <% end -%> return resourceComputeSecurityPolicyRead(d, meta) } diff --git a/mmv1/third_party/terraform/services/container/node_config.go.erb b/mmv1/third_party/terraform/services/container/node_config.go.erb index f4f0da9b05ed..7c55d6320e8d 100644 --- a/mmv1/third_party/terraform/services/container/node_config.go.erb +++ b/mmv1/third_party/terraform/services/container/node_config.go.erb @@ -109,6 +109,25 @@ func schemaNodeConfig() *schema.Schema { DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, Description: `The accelerator type resource name.`, }, + "gpu_driver_installation_config": &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ForceNew: true, + ConfigMode: schema.SchemaConfigModeAttr, + Description: `Configuration for auto installation of GPU driver.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "gpu_driver_version": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Mode for how the GPU driver is installed.`, + ValidateFunc: validation.StringInSlice([]string{"GPU_DRIVER_VERSION_UNSPECIFIED", "INSTALLATION_DISABLED", "DEFAULT", "LATEST"}, false), + }, + }, + }, + }, "gpu_partition_size": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -648,6 +667,13 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { GpuPartitionSize: data["gpu_partition_size"].(string), } + if v, ok := data["gpu_driver_installation_config"]; ok && len(v.([]interface{})) > 0 { + gpuDriverInstallationConfig := data["gpu_driver_installation_config"].([]interface{})[0].(map[string]interface{}) + guestAcceleratorConfig.GpuDriverInstallationConfig = &container.GPUDriverInstallationConfig{ + GpuDriverVersion: gpuDriverInstallationConfig["gpu_driver_version"].(string), + } + } + if v, ok := data["gpu_sharing_config"]; ok && len(v.([]interface{})) > 0 { gpuSharingConfig := data["gpu_sharing_config"].([]interface{})[0].(map[string]interface{}) guestAcceleratorConfig.GpuSharingConfig = &container.GPUSharingConfig{ @@ -1043,6 +1069,13 @@ func flattenContainerGuestAccelerators(c []*container.AcceleratorConfig) []map[s "type": accel.AcceleratorType, "gpu_partition_size": accel.GpuPartitionSize, } + if accel.GpuDriverInstallationConfig != nil { + accelerator["gpu_driver_installation_config"] = []map[string]interface{}{ + { + "gpu_driver_version": accel.GpuDriverInstallationConfig.GpuDriverVersion, + }, + } + } if accel.GpuSharingConfig != nil { accelerator["gpu_sharing_config"] = []map[string]interface{}{ { diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.erb b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.erb index 24b5485e9b7d..e748c1228419 100644 --- a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.erb +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.erb @@ -783,7 +783,7 @@ is set to true. Defaults to ZONAL.`, Optional: true, ForceNew: true, AtLeastOneOf: replicaConfigurationKeys, - Description: `Specifies if the replica is the failover target. If the field is set to true the replica will be designated as a failover replica. If the master instance fails, the replica instance will be promoted as the new master instance.`, + Description: `Specifies if the replica is the failover target. If the field is set to true the replica will be designated as a failover replica. If the master instance fails, the replica instance will be promoted as the new master instance. Not supported for Postgres`, }, "master_heartbeat_period": { Type: schema.TypeInt, diff --git a/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.erb b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.erb index 7e219382210a..ee1089569d84 100644 --- a/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.erb +++ b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.erb @@ -80,6 +80,13 @@ func resourceTagsLocationTagBindingCreate(d *schema.ResourceData, meta interface obj["tagValue"] = tagValueProp } + lockName, err := tpgresource.ReplaceVars(d, config, "tagBindings/{{parent}}") + if err != nil { + return err + } + transport_tpg.MutexStore.Lock(lockName) + defer transport_tpg.MutexStore.Unlock(lockName) + url, err := tpgresource.ReplaceVars(d, config, "{{TagsLocationBasePath}}tagBindings") log.Printf("url for TagsLocation: %s", url) if err != nil { @@ -248,6 +255,13 @@ func resourceTagsLocationTagBindingDelete(d *schema.ResourceData, meta interface billingProject := "" + lockName, err := tpgresource.ReplaceVars(d, config, "tagBindings/{{parent}}") + if err != nil { + return err + } + transport_tpg.MutexStore.Lock(lockName) + defer transport_tpg.MutexStore.Unlock(lockName) + url, err := tpgresource.ReplaceVars(d, config, "{{TagsLocationBasePath}}{{name}}") if err != nil { return err diff --git a/mmv1/third_party/terraform/tests/data_source_google_compute_image_test.go b/mmv1/third_party/terraform/tests/data_source_google_compute_image_test.go index 166a823ca51b..a4124eb868e6 100644 --- a/mmv1/third_party/terraform/tests/data_source_google_compute_image_test.go +++ b/mmv1/third_party/terraform/tests/data_source_google_compute_image_test.go @@ -70,6 +70,19 @@ func TestAccDataSourceComputeImageFilter(t *testing.T) { "self_link"), ), }, + { + Config: testAccDataSourceCustomImageFilterWithMostRecent(family, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.google_compute_image.from_filter", + "name", name+"-latest"), + resource.TestCheckResourceAttr("data.google_compute_image.from_filter", + "family", family), + resource.TestCheckResourceAttr("data.google_compute_image.from_filter", + "most_recent", "true"), + resource.TestCheckResourceAttrSet("data.google_compute_image.from_filter", + "self_link"), + ), + }, }, }) } @@ -163,3 +176,38 @@ data "google_compute_image" "from_filter" { `, family, name, name, name, name) } + +func testAccDataSourceCustomImageFilterWithMostRecent(family, name string) string { + return fmt.Sprintf(` +resource "google_compute_image" "image-first" { + family = "%s" + name = "%s-first" + source_disk = google_compute_disk.disk.self_link + labels = { + test = "%s" + } +} + +resource "google_compute_image" "image-latest" { + depends_on = [ google_compute_image.image-first ] + family = "%s" + name = "%s-latest" + source_disk = google_compute_disk.disk.self_link + labels = { + test = "%s" + } +} + +resource "google_compute_disk" "disk" { + name = "%s-disk" + zone = "us-central1-b" +} + +data "google_compute_image" "from_filter" { + project = google_compute_image.image-latest.project + filter = "labels.test = %s" + most_recent = true +} + +`, family, name, name, family, name, name, name, name) +} diff --git a/mmv1/third_party/terraform/tests/data_source_google_service_networking_peered_dns_domain_test.go b/mmv1/third_party/terraform/tests/data_source_google_service_networking_peered_dns_domain_test.go index 18ce120a8fa2..e883fe7fc0d1 100644 --- a/mmv1/third_party/terraform/tests/data_source_google_service_networking_peered_dns_domain_test.go +++ b/mmv1/third_party/terraform/tests/data_source_google_service_networking_peered_dns_domain_test.go @@ -66,7 +66,7 @@ resource "google_compute_network" "test" { } resource "google_compute_global_address" "host-private-access" { - name = "private-ip-alloc-host" + name = "%s-ip" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 24 @@ -116,5 +116,5 @@ data "google_service_networking_peered_dns_domain" "acceptance" { google_service_networking_peered_dns_domain.acceptance, ] } -`, project, project, org, billing, service, service, name, service, name, service) +`, project, project, org, billing, service, project, service, name, service, name, service) } diff --git a/mmv1/third_party/terraform/tests/data_source_vpc_access_connector_test.go b/mmv1/third_party/terraform/tests/data_source_vpc_access_connector_test.go index 2d6884dbc3bb..a9ca132fd1ee 100644 --- a/mmv1/third_party/terraform/tests/data_source_vpc_access_connector_test.go +++ b/mmv1/third_party/terraform/tests/data_source_vpc_access_connector_test.go @@ -40,6 +40,8 @@ resource "google_vpc_access_connector" "connector" { ip_cidr_range = "10.8.0.0/28" network = "default" region = "us-central1" + min_instances = 2 + max_instances = 3 } data "google_vpc_access_connector" "connector" { diff --git a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go index b25d19f7e3d0..6d8b1397cd95 100644 --- a/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go +++ b/mmv1/third_party/terraform/tests/resource_alloydb_cluster_test.go @@ -77,6 +77,7 @@ func TestAccAlloydbCluster_addAutomatedBackupPolicyAndInitialUser(t *testing.T) context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), + "hour": 23, } acctest.VcrTest(t, resource.TestCase{ @@ -117,6 +118,7 @@ func TestAccAlloydbCluster_deleteAutomatedBackupPolicyAndInitialUser(t *testing. context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), + "hour": 23, } acctest.VcrTest(t, resource.TestCase{ @@ -149,6 +151,37 @@ func TestAccAlloydbCluster_deleteAutomatedBackupPolicyAndInitialUser(t *testing. }) } +// Test if automatedBackupPolicy properly handles a startTime of 0 (aka midnight). Calling terraform plan +// after creating the cluster should not bring anything up. +func TestAccAlloydbCluster_AutomatedBackupPolicyHandlesMidnight(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "hour": 0, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckAlloydbClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context), + }, + { + ResourceName: "google_alloydb_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"initial_user", "cluster_id", "location"}, + }, + { + Config: testAccAlloydbCluster_alloydbClusterBasicExample(context), + }, + }, + }) +} + func testAccAlloydbCluster_withInitialUserAndAutomatedBackupPolicy(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_alloydb_cluster" "default" { @@ -170,7 +203,7 @@ resource "google_alloydb_cluster" "default" { days_of_week = ["MONDAY"] start_times { - hours = 23 + hours = %{hour} minutes = 0 seconds = 0 nanos = 0 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_env_keystore_alias_pkcs12_test.go b/mmv1/third_party/terraform/tests/resource_apigee_env_keystore_alias_pkcs12_test.go index c40d1ca6b824..083fd79a1db6 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_env_keystore_alias_pkcs12_test.go +++ b/mmv1/third_party/terraform/tests/resource_apigee_env_keystore_alias_pkcs12_test.go @@ -76,7 +76,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_environment_nodeconfig_test.go.erb b/mmv1/third_party/terraform/tests/resource_apigee_environment_nodeconfig_test.go.erb index 91ae9ca68489..4dc3fc5d1d53 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_environment_nodeconfig_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_apigee_environment_nodeconfig_test.go.erb @@ -97,7 +97,7 @@ resource "google_compute_network" "apigee_network" { resource "google_compute_global_address" "apigee_range" { provider = google-beta - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_flowhook_test.go b/mmv1/third_party/terraform/tests/resource_apigee_flowhook_test.go index 7c0d40591f4f..e2f45ee66434 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_flowhook_test.go +++ b/mmv1/third_party/terraform/tests/resource_apigee_flowhook_test.go @@ -75,7 +75,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_keystores_aliases_key_cert_file_test.go b/mmv1/third_party/terraform/tests/resource_apigee_keystores_aliases_key_cert_file_test.go index 5e73d98a269c..f9ccea011b4f 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_keystores_aliases_key_cert_file_test.go +++ b/mmv1/third_party/terraform/tests/resource_apigee_keystores_aliases_key_cert_file_test.go @@ -85,7 +85,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 @@ -206,7 +206,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_deployment_test.go b/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_deployment_test.go index 0ad76f502924..bda3fc6d5837 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_deployment_test.go +++ b/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_deployment_test.go @@ -86,7 +86,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_test.go b/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_test.go index 0161044fe51c..9a66757190e0 100644 --- a/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_test.go +++ b/mmv1/third_party/terraform/tests/resource_apigee_sharedflow_test.go @@ -86,7 +86,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 @@ -192,7 +192,7 @@ resource "google_compute_network" "apigee_network" { } resource "google_compute_global_address" "apigee_range" { - name = "apigee-range" + name = "tf-test-apigee-range%{random_suffix}" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 16 diff --git a/mmv1/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go b/mmv1/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go index cbd3afaa1e90..13729057f73b 100644 --- a/mmv1/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go +++ b/mmv1/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go @@ -177,6 +177,8 @@ resource "google_vpc_access_connector" "bar" { region = "us-central1" ip_cidr_range = "10.8.0.0/28" network = "default" + min_instances = 3 + max_instances = 10 } resource "google_app_engine_standard_app_version" "foo" { diff --git a/mmv1/third_party/terraform/tests/resource_bigquery_table_test.go b/mmv1/third_party/terraform/tests/resource_bigquery_table_test.go index 64dce7c324fb..e3b2d380b937 100644 --- a/mmv1/third_party/terraform/tests/resource_bigquery_table_test.go +++ b/mmv1/third_party/terraform/tests/resource_bigquery_table_test.go @@ -246,6 +246,34 @@ func TestAccBigQueryTable_AvroPartitioning(t *testing.T) { }) } +func TestAccBigQueryExternalDataTable_json(t *testing.T) { + t.Parallel() + bucketName := testBucketName(t) + resourceName := "google_bigquery_table.test" + datasetID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) + tableID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigQueryTableDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigQueryTableJson(datasetID, tableID, bucketName, "UTF-8"), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"external_data_configuration.0.schema", "deletion_protection"}, + }, + { + Config: testAccBigQueryTableJson(datasetID, tableID, bucketName, "UTF-16BE"), + }, + }, + }) +} + func TestAccBigQueryTable_RangePartitioning(t *testing.T) { t.Parallel() resourceName := "google_bigquery_table.test" @@ -480,6 +508,30 @@ func TestAccBigQueryExternalDataTable_parquet(t *testing.T) { }) } +func TestAccBigQueryExternalDataTable_parquetOptions(t *testing.T) { + t.Parallel() + + bucketName := testBucketName(t) + objectName := fmt.Sprintf("tf_test_%s.gz.parquet", acctest.RandString(t, 10)) + + datasetID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) + tableID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigQueryTableDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigQueryTableFromGCSParquetOptions(datasetID, tableID, bucketName, objectName, true, true), + }, + { + Config: testAccBigQueryTableFromGCSParquetOptions(datasetID, tableID, bucketName, objectName, false, false), + }, + }, + }) +} + func TestAccBigQueryExternalDataTable_objectTable(t *testing.T) { t.Parallel() @@ -1581,6 +1633,46 @@ resource "google_bigquery_table" "test" { `, datasetID, bucketName, objectName, tableID) } +func testAccBigQueryTableFromGCSParquetOptions(datasetID, tableID, bucketName, objectName string, enum, list bool) string { + return fmt.Sprintf(` +resource "google_bigquery_dataset" "test" { + dataset_id = "%s" +} + +resource "google_storage_bucket" "test" { + name = "%s" + location = "US" + force_destroy = true +} + +resource "google_storage_bucket_object" "test" { + name = "%s" + source = "./test-fixtures/bigquerytable/test.parquet.gzip" + bucket = google_storage_bucket.test.name +} + +resource "google_bigquery_table" "test" { + deletion_protection = false + table_id = "%s" + dataset_id = google_bigquery_dataset.test.dataset_id + external_data_configuration { + autodetect = false + source_format = "PARQUET" + reference_file_schema_uri = "gs://${google_storage_bucket.test.name}/${google_storage_bucket_object.test.name}" + + parquet_options { + enum_as_string = "%t" + enable_list_inference = "%t" + } + + source_uris = [ + "gs://${google_storage_bucket.test.name}/*", + ] + } +} +`, datasetID, bucketName, objectName, tableID, enum, list) +} + func testAccBigQueryTableFromGCSObjectTable(connectionID, datasetID, tableID, bucketName, objectName string) string { return fmt.Sprintf(` resource "google_bigquery_connection" "test" { @@ -1797,6 +1889,62 @@ resource "google_bigquery_table" "test" { `, datasetID, bucketName, objectName, content, connectionID, projectID, tableID, schema) } +func testAccBigQueryTableJson(bucketName, datasetID, tableID, encoding string) string { + return fmt.Sprintf(` +resource "google_storage_bucket" "test" { + name = "%s" + location = "US" + force_destroy = true +} + +resource "google_storage_bucket_object" "test" { + name = "key1=20200330/data.json" + content = "{\"name\":\"test\", \"last_modification\":\"2020-04-01\"}" + bucket = google_storage_bucket.test.name +} + +resource "google_bigquery_dataset" "test" { + dataset_id = "%s" +} + +resource "google_bigquery_table" "test" { + deletion_protection = false + table_id = "%s" + dataset_id = google_bigquery_dataset.test.dataset_id + + external_data_configuration { + source_format = "NEWLINE_DELIMITED_JSON" + autodetect = false + source_uris= ["gs://${google_storage_bucket.test.name}/*"] + + json_options { + encoding = "%s" + } + + hive_partitioning_options { + mode = "CUSTOM" + source_uri_prefix = "gs://${google_storage_bucket.test.name}/{key1:STRING}" + require_partition_filter = true + } + + schema = < +func TestAccComputeDisk_pdHyperDiskEnableConfidentialCompute(t *testing.T) { + t.Parallel() + + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + "kms": BootstrapKMSKey(t), + "disk_size": 64, + "confidential_compute": true, + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeDiskDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeDisk_pdHyperDiskEnableConfidentialCompute(context), + Check: resource.ComposeTestCheckFunc( + testAccCheckEncryptionKey(t, "google_compute_disk.foobar", &disk), + ), + + }, + { + ResourceName: "google_compute_disk.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +<% end -%> + + func TestAccComputeDisk_deleteDetach(t *testing.T) { t.Parallel() @@ -1024,6 +1059,24 @@ resource "google_compute_instance_group_manager" "manager" { `, diskName, mgrName) } +func testAccComputeDisk_pdHyperDiskEnableConfidentialCompute(context map[string]interface{}) string { + return Nprintf(` + resource "google_compute_disk" "foobar" { + name = "tf-test-ecc-%{random_suffix}" + size = %{disk_size} + type = "hyperdisk-balanced" + zone = "us-central1-a" + enable_confidential_compute = %{confidential_compute} + + disk_encryption_key { + kms_key_self_link = "%{kms}" + } + + } +`, context) +} + + func testAccComputeDisk_pdHyperDiskProvisionedIopsLifeCycle(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_compute_disk" "foobar" { diff --git a/mmv1/third_party/terraform/tests/resource_compute_forwarding_rule_test.go.erb b/mmv1/third_party/terraform/tests/resource_compute_forwarding_rule_test.go.erb index 73dde0ef3479..7249c204f2f4 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_forwarding_rule_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_compute_forwarding_rule_test.go.erb @@ -43,9 +43,9 @@ func TestAccComputeForwardingRule_update(t *testing.T) { func TestAccComputeForwardingRule_ip(t *testing.T) { t.Parallel() - addrName := fmt.Sprintf("tf-%s", acctest.RandString(t, 10)) - poolName := fmt.Sprintf("tf-%s", acctest.RandString(t, 10)) - ruleName := fmt.Sprintf("tf-%s", acctest.RandString(t, 10)) + addrName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + poolName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + ruleName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) addressRefFieldRaw := "address" addressRefFieldID := "id" diff --git a/mmv1/third_party/terraform/tests/resource_compute_instance_test.go.erb b/mmv1/third_party/terraform/tests/resource_compute_instance_test.go.erb index 97869a3e359f..3617d08fd662 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_instance_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_compute_instance_test.go.erb @@ -28,6 +28,74 @@ import ( <% end -%> ) +func TestMinCpuPlatformDiffSuppress(t *testing.T) { + cases := map[string]struct { + Old, New string + ExpectDiffSuppress bool + }{ + "state: empty, conf: AUTOMATIC": { + Old: "", + New: "AUTOMATIC", + ExpectDiffSuppress: true, + }, + "state: empty, conf: automatic": { + Old: "", + New: "automatic", + ExpectDiffSuppress: true, + }, + "state: empty, conf: AuToMaTiC": { + Old: "", + New: "AuToMaTiC", + ExpectDiffSuppress: true, + }, + "state: empty, conf: Intel Haswell": { + Old: "", + New: "Intel Haswell", + ExpectDiffSuppress: false, + }, + // This case should never happen due to the field being + // Optional + Computed; however, including for completeness. + "state: Intel Haswell, conf: empty": { + Old: "Intel Haswell", + New: "", + ExpectDiffSuppress: false, + }, + // These cases should never happen given current API behavior; testing + // in case API behavior changes in the future. + "state: AUTOMATIC, conf: Intel Haswell": { + Old: "AUTOMATIC", + New: "Intel Haswell", + ExpectDiffSuppress: false, + }, + "state: Intel Haswell, conf: AUTOMATIC": { + Old: "Intel Haswell", + New: "AUTOMATIC", + ExpectDiffSuppress: false, + }, + "state: AUTOMATIC, conf: empty": { + Old: "AUTOMATIC", + New: "", + ExpectDiffSuppress: true, + }, + "state: automatic, conf: empty": { + Old: "automatic", + New: "", + ExpectDiffSuppress: true, + }, + "state: AuToMaTiC, conf: empty": { + Old: "AuToMaTiC", + New: "", + ExpectDiffSuppress: true, + }, + } + + for tn, tc := range cases { + if tpgcompute.ComputeInstanceMinCpuPlatformEmptyOrAutomaticDiffSuppress("min_cpu_platform", tc.Old, tc.New, nil) != tc.ExpectDiffSuppress { + t.Errorf("bad: %s, %q => %q expect DiffSuppress to return %t", tn, tc.Old, tc.New, tc.ExpectDiffSuppress) + } + } +} + func computeInstanceImportStep(zone, instanceName string, additionalImportIgnores []string) resource.TestStep { // metadata is only read into state if set in the config // importing doesn't know whether metadata.startup_script vs metadata_startup_script is set in the config, @@ -1436,7 +1504,15 @@ func TestAccComputeInstance_minCpuPlatform(t *testing.T) { testAccCheckComputeInstanceHasMinCpuPlatform(&instance, "Intel Haswell"), ), }, - computeInstanceImportStep("us-east1-d", instanceName, []string{}), + computeInstanceImportStep("us-east1-d", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_minCpuPlatform_remove(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceHasMinCpuPlatform(&instance, ""), + ), + }, + computeInstanceImportStep("us-east1-d", instanceName, []string{"allow_stopping_for_update"}), }, }) } @@ -5306,6 +5382,35 @@ resource "google_compute_instance" "foobar" { } min_cpu_platform = "Intel Haswell" + allow_stopping_for_update = true +} +`, instance) +} + +func testAccComputeInstance_minCpuPlatform_remove(instance string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "e2-micro" + zone = "us-east1-d" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + min_cpu_platform = "AuToMaTiC" + allow_stopping_for_update = true } `, instance) } diff --git a/mmv1/third_party/terraform/tests/resource_compute_region_backend_service_test.go.erb b/mmv1/third_party/terraform/tests/resource_compute_region_backend_service_test.go.erb index a1d3a43253c7..56ceb1080a10 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_region_backend_service_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_compute_region_backend_service_test.go.erb @@ -1055,3 +1055,54 @@ resource "google_compute_health_check" "health_check" { `, serviceName, checkName) } <% end -%> + +<% unless version == 'ga' -%> +func TestAccComputeRegionBackendService_withSecurityPolicy(t *testing.T) { + t.Parallel() + + serviceName := fmt.Sprintf("tf-test-%s", RandString(t, 10)) + polName := fmt.Sprintf("tf-test-%s", RandString(t, 10)) + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeBackendServiceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionBackendService_withSecurityPolicy(serviceName, polName, "google_compute_region_security_policy.policy.self_link"), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionBackendService_withSecurityPolicy(serviceName, polName, "\"\""), + }, + { + ResourceName: "google_compute_region_backend_service.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeRegionBackendService_withSecurityPolicy(serviceName, polName, polLink string) string { + return fmt.Sprintf(` +resource "google_compute_region_backend_service" "foobar" { + name = "%s" + region = "us-central1" + security_policy = %s + load_balancing_scheme = "EXTERNAL_MANAGED" +} + +resource "google_compute_region_security_policy" "policy" { + name = "%s" + region = "us-central1" + description = "basic security policy" + type = "CLOUD_ARMOR" +} +`, serviceName, polLink, polName) +} +<% end -%> diff --git a/mmv1/third_party/terraform/tests/resource_compute_router_nat_test.go.erb b/mmv1/third_party/terraform/tests/resource_compute_router_nat_test.go.erb index 53717e6cd87e..d1b10b6c004d 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_router_nat_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_compute_router_nat_test.go.erb @@ -731,7 +731,7 @@ resource "google_compute_subnetwork" "foobar" { } resource "google_compute_address" "foobar" { - name = "router-nat-%s-addr" + name = "%s-router-nat-addr" region = google_compute_subnetwork.foobar.region } @@ -774,7 +774,7 @@ resource "google_compute_subnetwork" "foobar" { } resource "google_compute_address" "foobar" { - name = "router-nat-%s-addr" + name = "%s-router-nat-addr" region = google_compute_subnetwork.foobar.region } @@ -819,7 +819,7 @@ resource "google_compute_subnetwork" "foobar" { } resource "google_compute_address" "foobar" { - name = "router-nat-%s-addr" + name = "%s-router-nat-addr" region = google_compute_subnetwork.foobar.region } diff --git a/mmv1/third_party/terraform/tests/resource_compute_security_policy_test.go.erb b/mmv1/third_party/terraform/tests/resource_compute_security_policy_test.go.erb index b87112a54b6a..23d4ceffe327 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_security_policy_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_compute_security_policy_test.go.erb @@ -364,6 +364,14 @@ func TestAccComputeSecurityPolicy_EnforceOnKeyUpdates(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckComputeSecurityPolicyDestroyProducer(t), Steps: []resource.TestStep{ + { + Config: testAccComputeSecurityPolicy_withRateLimitOptions_withoutRateLimitOptions(spName), + }, + { + ResourceName: "google_compute_security_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKeyName(spName), }, @@ -396,10 +404,19 @@ func TestAccComputeSecurityPolicy_EnforceOnKeyUpdates(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + Config: testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKeyName(spName), + }, + { + ResourceName: "google_compute_security_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, }, }) } + <% end -%> func TestAccComputeSecurityPolicy_withRecaptchaOptionsConfig(t *testing.T) { @@ -1267,6 +1284,27 @@ resource "google_compute_security_policy" "policy" { `, spName) } +func testAccComputeSecurityPolicy_withRateLimitOptions_withoutRateLimitOptions(spName string) string { + return fmt.Sprintf(` +resource "google_compute_security_policy" "policy" { + name = "%s" + description = "throttle rule with enforce_on_key_configs" + + rule { + action = "deny(403)" + priority = "2147483647" + match { + versioned_expr = "SRC_IPS_V1" + config { + src_ip_ranges = ["*"] + } + } + description = "default rule" + } +} +`, spName) +} + func testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKeyName(spName string) string { return fmt.Sprintf(` resource "google_compute_security_policy" "policy" { diff --git a/mmv1/third_party/terraform/tests/resource_container_node_pool_test.go.erb b/mmv1/third_party/terraform/tests/resource_container_node_pool_test.go.erb index f8c51ab791f3..1e46eaac15b4 100644 --- a/mmv1/third_party/terraform/tests/resource_container_node_pool_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_container_node_pool_test.go.erb @@ -2739,6 +2739,9 @@ resource "google_container_node_pool" "np_with_gpu" { type = "nvidia-tesla-a100" gpu_partition_size = "1g.5gb" count = 1 + gpu_driver_installation_config { + gpu_driver_version = "LATEST" + } gpu_sharing_config { gpu_sharing_strategy = "TIME_SHARING" max_shared_clients_per_gpu = 2 diff --git a/mmv1/third_party/terraform/tests/resource_dataplex_task_test.go b/mmv1/third_party/terraform/tests/resource_dataplex_task_test.go new file mode 100644 index 000000000000..cc4ff4cee2f2 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_dataplex_task_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccDataplexTaskDataplexTask_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_name": acctest.GetTestProjectFromEnv(), + "random_suffix": RandString(t, 10), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataplexTaskDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataplexTask_dataplexTaskPrimary(context), + }, + { + ResourceName: "google_dataplex_task.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "lake", "task_id"}, + }, + { + Config: testAccDataplexTask_dataplexTaskPrimaryUpdate(context), + }, + { + ResourceName: "google_dataplex_task.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "lake", "task_id"}, + }, + }, + }) +} + +func testAccDataplexTask_dataplexTaskPrimary(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_project" "project" { + +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_task" "example" { + + task_id = "tf-test-task%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + trigger_spec { + type = "ON_DEMAND" + } + + execution_spec { + service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" + } + + spark { + python_script_file = "gs://dataproc-examples/pyspark/hello-world/hello-world.py" + } + + project = "%{project_name}" + +} +`, context) +} + +func testAccDataplexTask_dataplexTaskPrimaryUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_project" "project" { + +} + +resource "google_dataplex_lake" "example" { + name = "tf-test-lake%{random_suffix}" + location = "us-central1" + project = "%{project_name}" +} + + +resource "google_dataplex_task" "example" { + + task_id = "tf-test-task%{random_suffix}" + location = "us-central1" + lake = google_dataplex_lake.example.name + trigger_spec { + type = "ON_DEMAND" + } + + execution_spec { + service_account = "${data.google_project.project.number}-compute@developer.gserviceaccount.com" + } + + spark { + python_script_file = "gs://dataplex-clouddq-api-integration-test/clouddq_pyspark_driver.py" + } + + project = "%{project_name}" + +} +`, context) +} diff --git a/mmv1/third_party/terraform/tests/resource_google_security_scanner_scan_config_test.go.erb b/mmv1/third_party/terraform/tests/resource_google_security_scanner_scan_config_test.go.erb index 8ba783015236..843f4b039909 100644 --- a/mmv1/third_party/terraform/tests/resource_google_security_scanner_scan_config_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_google_security_scanner_scan_config_test.go.erb @@ -54,11 +54,11 @@ func TestAccSecurityScannerScanConfig_scanConfigUpdate(t *testing.T) { func testAccSecurityScannerScanConfig(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_compute_address" "scanner_static_ip" { - name = "scan-static-ip-%{random_suffix}" + name = "tf-test-scan-static-ip-%{random_suffix}" } resource "google_compute_address" "scanner_static_ip_update" { - name = "scan-static-ip-%{random_suffix2}" + name = "tf-test-scan-static-ip-%{random_suffix2}" } resource "google_security_scanner_scan_config" "terraform-scan-config" { diff --git a/mmv1/third_party/terraform/tests/resource_google_service_networking_peered_dns_domain_test.go b/mmv1/third_party/terraform/tests/resource_google_service_networking_peered_dns_domain_test.go index 7029ae1a0c18..ae2f6a83e100 100644 --- a/mmv1/third_party/terraform/tests/resource_google_service_networking_peered_dns_domain_test.go +++ b/mmv1/third_party/terraform/tests/resource_google_service_networking_peered_dns_domain_test.go @@ -15,7 +15,7 @@ func TestAccServiceNetworkingPeeredDNSDomain_basic(t *testing.T) { billingId := envvar.GetTestBillingAccountFromEnv(t) project := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) - name := fmt.Sprintf("test-name-%d", acctest.RandInt(t)) + name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) service := "servicenetworking.googleapis.com" acctest.VcrTest(t, resource.TestCase{ @@ -57,7 +57,7 @@ resource "google_compute_network" "test" { } resource "google_compute_global_address" "host-private-access" { - name = "private-ip-alloc-host" + name = "%s-ip" purpose = "VPC_PEERING" address_type = "INTERNAL" prefix_length = 24 @@ -95,5 +95,5 @@ resource "google_service_networking_peered_dns_domain" "test" { google_service_networking_connection.host-private-access, ] } -`, project, project, org, billing, service, service, name, service) +`, project, project, org, billing, service, project, service, name, service) } diff --git a/mmv1/third_party/terraform/tests/resource_looker_instance_test.go b/mmv1/third_party/terraform/tests/resource_looker_instance_test.go new file mode 100644 index 000000000000..3e36d8bdfc41 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_looker_instance_test.go @@ -0,0 +1,42 @@ +package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccLookerInstance_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckLookerInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccLookerInstance_lookerInstanceBasicExample(context), + }, + { + ResourceName: "google_looker_instance.looker-instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"oauth_config", "region"}, + }, + { + Config: testAccLookerInstance_lookerInstanceFullExample(context), + }, + { + ResourceName: "google_looker_instance.looker-instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"oauth_config", "region"}, + }, + }, + }) +} diff --git a/mmv1/third_party/terraform/tests/resource_vpc_access_connector_test.go b/mmv1/third_party/terraform/tests/resource_vpc_access_connector_test.go index f7104c6d8227..2d9f510ebf84 100644 --- a/mmv1/third_party/terraform/tests/resource_vpc_access_connector_test.go +++ b/mmv1/third_party/terraform/tests/resource_vpc_access_connector_test.go @@ -31,6 +31,38 @@ func TestAccVPCAccessConnector_vpcAccessConnectorThroughput(t *testing.T) { }) } +func TestAccVPCAccessConnector_vpcAccessConnectorMachineAndInstancesChanged(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": RandString(t, 10), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckVPCAccessConnectorDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVPCAccessConnector_vpcAccessConnectorThroughput(context), + }, + { + ResourceName: "google_vpc_access_connector.connector", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccVPCAccessConnector_vpcAccessConnectorMachineAndInstancesChanged(context), + }, + { + ResourceName: "google_vpc_access_connector.connector", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccVPCAccessConnector_vpcAccessConnectorThroughput(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_vpc_access_connector" "connector" { @@ -57,3 +89,30 @@ resource "google_compute_network" "custom_test" { } `, context) } + +func testAccVPCAccessConnector_vpcAccessConnectorMachineAndInstancesChanged(context map[string]interface{}) string { + return Nprintf(` +resource "google_vpc_access_connector" "connector" { + name = "tf-test-vpc-con%{random_suffix}" + subnet { + name = google_compute_subnetwork.custom_test.name + } + machine_type = "e2-micro" + min_instances = 3 + max_instances = 5 + region = "us-central1" +} + +resource "google_compute_subnetwork" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + ip_cidr_range = "10.2.0.0/28" + region = "us-central1" + network = google_compute_network.custom_test.id +} + +resource "google_compute_network" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} diff --git a/mmv1/third_party/terraform/transport/config_test.go b/mmv1/third_party/terraform/transport/config_test.go index ded57d0f2240..d1544bdbde71 100644 --- a/mmv1/third_party/terraform/transport/config_test.go +++ b/mmv1/third_party/terraform/transport/config_test.go @@ -39,6 +39,9 @@ func TestHandleSDKDefaults_BillingProject(t *testing.T) { ExpectedValue: "my-billing-project-from-env", }, "when no values are provided via config or environment variables, the field remains unset without error": { + EnvVariables: map[string]string{ + "GOOGLE_BILLING_PROJECT": "", // GOOGLE_BILLING_PROJECT unset + }, ValueNotProvided: true, }, } @@ -101,13 +104,17 @@ func TestHandleSDKDefaults_Region(t *testing.T) { "region value set in the provider config is not overridden by ENVs": { ConfigValue: "region-from-config", EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", + "GOOGLE_REGION": "region-from-env", + "GCLOUD_REGION": "", // GCLOUD_REGION unset + "CLOUDSDK_COMPUTE_REGION": "", // CLOUDSDK_COMPUTE_REGION unset }, ExpectedValue: "region-from-config", }, "region can be set by environment variable, when no value supplied via the config": { EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", + "GOOGLE_REGION": "region-from-env", + "GCLOUD_REGION": "", // GCLOUD_REGION unset + "CLOUDSDK_COMPUTE_REGION": "", // CLOUDSDK_COMPUTE_REGION unset }, ExpectedValue: "region-from-env", }, @@ -121,7 +128,7 @@ func TestHandleSDKDefaults_Region(t *testing.T) { }, "when multiple region environment variables are provided, `GCLOUD_REGION` is used second": { EnvVariables: map[string]string{ - // GOOGLE_REGION unset + "GOOGLE_REGION": "", // GOOGLE_REGION unset "GCLOUD_REGION": "project-from-GCLOUD_REGION", "CLOUDSDK_COMPUTE_REGION": "project-from-CLOUDSDK_COMPUTE_REGION", }, @@ -129,13 +136,18 @@ func TestHandleSDKDefaults_Region(t *testing.T) { }, "when multiple region environment variables are provided, `CLOUDSDK_COMPUTE_REGION` is the last-used ENV": { EnvVariables: map[string]string{ - // GOOGLE_REGION unset - // GCLOUD_REGION unset + "GOOGLE_REGION": "", // GOOGLE_REGION unset + "GCLOUD_REGION": "", // GCLOUD_REGION unset "CLOUDSDK_COMPUTE_REGION": "project-from-CLOUDSDK_COMPUTE_REGION", }, ExpectedValue: "project-from-CLOUDSDK_COMPUTE_REGION", }, "when no values are provided via config or environment variables, the field remains unset without error": { + EnvVariables: map[string]string{ + "GOOGLE_REGION": "", // GOOGLE_REGION unset + "GCLOUD_REGION": "", // GCLOUD_REGION unset + "CLOUDSDK_COMPUTE_REGION": "", // CLOUDSDK_COMPUTE_REGION unset + }, ValueNotProvided: true, }, } @@ -198,13 +210,17 @@ func TestHandleSDKDefaults_Zone(t *testing.T) { "region value set in the provider config is not overridden by ENVs": { ConfigValue: "zone-from-config", EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-env", + "GOOGLE_ZONE": "zone-from-env", + "GCLOUD_ZONE": "", // GCLOUD_ZONE unset + "CLOUDSDK_COMPUTE_ZONE": "", // CLOUDSDK_COMPUTE_ZONE unset }, ExpectedValue: "zone-from-config", }, "zone can be set by environment variable, when no value supplied via the config": { EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-env", + "GOOGLE_ZONE": "zone-from-env", + "GCLOUD_ZONE": "", // GCLOUD_ZONE unset + "CLOUDSDK_COMPUTE_ZONE": "", // CLOUDSDK_COMPUTE_ZONE unset }, ExpectedValue: "zone-from-env", }, @@ -218,7 +234,7 @@ func TestHandleSDKDefaults_Zone(t *testing.T) { }, "when multiple zone environment variables are provided, `GCLOUD_ZONE` is used second": { EnvVariables: map[string]string{ - // GOOGLE_ZONE unset + "GOOGLE_ZONE": "", // GOOGLE_ZONE unset "GCLOUD_ZONE": "zone-from-GCLOUD_ZONE", "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", }, @@ -226,13 +242,18 @@ func TestHandleSDKDefaults_Zone(t *testing.T) { }, "when multiple zone environment variables are provided, `CLOUDSDK_COMPUTE_ZONE` is the last-used ENV": { EnvVariables: map[string]string{ - // GOOGLE_ZONE unset - // GCLOUD_ZONE unset + "GOOGLE_ZONE": "", // GOOGLE_ZONE unset + "GCLOUD_ZONE": "", // GCLOUD_ZONE unset "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", }, ExpectedValue: "zone-from-CLOUDSDK_COMPUTE_ZONE", }, "when no values are provided via config or environment variables, the field remains unset without error": { + EnvVariables: map[string]string{ + "GOOGLE_ZONE": "", // GOOGLE_ZONE unset + "GCLOUD_ZONE": "", // GCLOUD_ZONE unset + "CLOUDSDK_COMPUTE_ZONE": "", // CLOUDSDK_COMPUTE_ZONE unset + }, ValueNotProvided: true, }, } @@ -334,6 +355,9 @@ func TestHandleSDKDefaults_UserProjectOverride(t *testing.T) { ExpectError: true, }, "when no values are provided via config or environment variables, the field remains unset without error": { + EnvVariables: map[string]string{ + "USER_PROJECT_OVERRIDE": "", // USER_PROJECT_OVERRIDE unset + }, ValueNotProvided: true, }, } @@ -405,6 +429,9 @@ func TestHandleSDKDefaults_RequestReason(t *testing.T) { ExpectedValue: "request-reason-from-env", }, "when no values are provided via config or environment variables, the field remains unset without error": { + EnvVariables: map[string]string{ + "CLOUDSDK_CORE_REQUEST_REASON": "", // CLOUDSDK_CORE_REQUEST_REASON unset + }, ValueNotProvided: true, }, } diff --git a/mmv1/third_party/terraform/transport/error_retry_predicates.go b/mmv1/third_party/terraform/transport/error_retry_predicates.go index 58e328c6918f..5b64594d86a4 100644 --- a/mmv1/third_party/terraform/transport/error_retry_predicates.go +++ b/mmv1/third_party/terraform/transport/error_retry_predicates.go @@ -271,6 +271,16 @@ func IsMonitoringConcurrentEditError(err error) (bool, string) { return false, "" } +// Retry if Monitoring operation returns a 403 +func IsMonitoringPermissionError(err error) (bool, string) { + if gerr, ok := err.(*googleapi.Error); ok { + if gerr.Code == 403 { + return true, "Waiting for project to be ready for metrics scope" + } + } + return false, "" +} + // Retry if KMS CryptoKeyVersions returns a 400 for PENDING_GENERATION func IsCryptoKeyVersionsPendingGeneration(err error) (bool, string) { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 400 { diff --git a/mmv1/third_party/terraform/website/docs/d/compute_image.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_image.html.markdown index 72707c9bd6cc..e9cdc9616ad6 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_image.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_image.html.markdown @@ -36,7 +36,8 @@ The following arguments are supported: Exactly one of `name`, `family` or `filter` must be specified. If `name` is specified, it will fetch the corresponding image. If `family` is specified, it will return the latest image that is part of an image family and is not deprecated. If you specify `filter`, your -filter must return exactly one image. Filter syntax can be found [here](https://cloud.google.com/compute/docs/reference/rest/v1/images/list) in the filter section. +filter must return exactly one image unless you use `most_recent`. +Filter syntax can be found [here](https://cloud.google.com/compute/docs/reference/rest/v1/images/list) in the filter section. - - - @@ -44,6 +45,9 @@ filter must return exactly one image. Filter syntax can be found [here](https:// provided, the provider project is used. If you are using a [public base image][pubimg], be sure to specify the correct Image Project. +* `most_recent` - (Optional) A boolean to indicate either to take to most recent image if your filter + returns more than one image. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/mmv1/third_party/terraform/website/docs/d/compute_instance.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_instance.html.markdown index 2a3e1d03f404..d478a3eca5ae 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_instance.html.markdown @@ -61,7 +61,7 @@ The following arguments are supported: * `metadata` - Metadata key/value pairs made available within the instance. -* `min_cpu_platform` - The minimum CPU platform specified for the VM instance. +* `min_cpu_platform` - The minimum CPU platform specified for the VM instance. Set to "AUTOMATIC" to remove a previously-set value. * `scheduling` - The scheduling strategy being used by the instance. Structure is [documented below](#nested_scheduling) diff --git a/mmv1/third_party/terraform/website/docs/r/bigquery_table.html.markdown b/mmv1/third_party/terraform/website/docs/r/bigquery_table.html.markdown index 557680aab8d9..cf943e567cb0 100644 --- a/mmv1/third_party/terraform/website/docs/r/bigquery_table.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/bigquery_table.html.markdown @@ -160,6 +160,12 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete * `csv_options` (Optional) - Additional properties to set if `source_format` is set to "CSV". Structure is [documented below](#nested_csv_options). +* `json_options` (Optional) - Additional properties to set if + `source_format` is set to "JSON". Structure is [documented below](#nested_json_options). + +* `parquet_options` (Optional) - Additional properties to set if + `source_format` is set to "PARQUET". Structure is [documented below](#nested_parquet_options). + * `google_sheets_options` (Optional) - Additional options if `source_format` is set to "GOOGLE_SHEETS". Structure is [documented below](#nested_google_sheets_options). @@ -172,7 +178,6 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete * `avro_options` (Optional) - Additional options if `source_format` is set to "AVRO". Structure is [documented below](#nested_avro_options). - * `ignore_unknown_values` (Optional) - Indicates if BigQuery should allow extra values that are not represented in the table schema. If true, the extra values are ignored. If false, records with @@ -234,6 +239,10 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete * `skip_leading_rows` (Optional) - The number of rows at the top of a CSV file that BigQuery will skip when reading the data. +The `json_options` block supports: + +* `encoding` (Optional) - The character encoding of the data. The supported values are UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, and UTF-32LE. The default value is UTF-8. + The `google_sheets_options` block supports: * `range` (Optional) - Range of a sheet to query from. Only used when @@ -255,7 +264,7 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete partitioning on an unsupported format will lead to an error. Currently supported formats are: JSON, CSV, ORC, Avro and Parquet. * CUSTOM: when set to `CUSTOM`, you must encode the partition key schema within the `source_uri_prefix` by setting `source_uri_prefix` to `gs://bucket/path_to_table/{key1:TYPE1}/{key2:TYPE2}/{key3:TYPE3}`. - + * `require_partition_filter` - (Optional) If set to true, queries over this table require a partition filter that can be used for partition elimination to be specified. @@ -274,7 +283,12 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete * `use_avro_logical_types` (Optional) - If is set to true, indicates whether to interpret logical types as the corresponding BigQuery data type (for example, TIMESTAMP), instead of using the raw type (for example, INTEGER). - + +The `parquet_options` block supports: + +* `enum_as_string` (Optional) - Indicates whether to infer Parquet ENUM logical type as STRING instead of BYTES by default. + +* `enable_list_inference` (Optional) - Indicates whether to use schema inference specifically for Parquet LIST logical type. The `time_partitioning` block supports: diff --git a/mmv1/third_party/terraform/website/docs/r/bigtable_instance.html.markdown b/mmv1/third_party/terraform/website/docs/r/bigtable_instance.html.markdown index a7ccdaeed179..6536a90b7800 100644 --- a/mmv1/third_party/terraform/website/docs/r/bigtable_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/bigtable_instance.html.markdown @@ -113,8 +113,8 @@ in Terraform state, a `terraform destroy` or `terraform apply` that would delete specified, the provider zone is used. Each cluster must have a different zone in the same region. Zones that support Bigtable instances are noted on the [Cloud Bigtable locations page](https://cloud.google.com/bigtable/docs/locations). -* `num_nodes` - (Optional) The number of nodes in your Cloud Bigtable cluster. -Required, with a minimum of `1` for each cluster in an instance. +* `num_nodes` - (Optional) The number of nodes in the cluster. +If no value is set, Cloud Bigtable automatically allocates nodes based on your data footprint and optimized for 50% storage utilization. * `autoscaling_config` - (Optional) [Autoscaling](https://cloud.google.com/bigtable/docs/autoscaling#parameters) config for the cluster, contains the following arguments: diff --git a/mmv1/third_party/terraform/website/docs/r/bigtable_table.html.markdown b/mmv1/third_party/terraform/website/docs/r/bigtable_table.html.markdown index 426dad25c46c..ce88083ec89b 100644 --- a/mmv1/third_party/terraform/website/docs/r/bigtable_table.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/bigtable_table.html.markdown @@ -50,6 +50,8 @@ resource "google_bigtable_table" "table" { column_family { family = "family-second" } + + change_stream_retention = "24h0m0s" } ``` @@ -72,6 +74,8 @@ to delete/recreate the entire `google_bigtable_table` resource. * `deletion_protection` - (Optional) A field to make the table protected against data loss i.e. when set to PROTECTED, deleting the table, the column families in the table, and the instance containing the table would be prohibited. If not provided, deletion protection will be set to UNPROTECTED. +* `change_stream_retention` - (Optional) Duration to retain change stream data for the table. Set to 0 to disable. Must be between 1 and 7 days. + ----- `column_family` supports the following arguments: diff --git a/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown b/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown index 863c2c4f7990..fb2253c9c538 100644 --- a/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/composer_environment.html.markdown @@ -682,8 +682,9 @@ The `config` block supports: * `resilience_mode` - (Optional, Cloud Composer 2.1.15 or newer only) The resilience mode states whether high resilience is enabled for - the environment or not. Value for resilience mode is `HIGH_RESILIENCE`. - If unspecified, defaults to standard resilience. + the environment or not. Values for resilience mode are `HIGH_RESILIENCE` + for high resilience and `STANDARD_RESILIENCE` for standard + resilience. * `master_authorized_networks_config` - (Optional) diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown index df41e17b9104..d4ca086606d7 100644 --- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown @@ -948,6 +948,17 @@ sole_tenant_config { * `count` (Required) - The number of the guest accelerator cards exposed to this instance. +* `gpu_driver_installation_config` (Optional) - Configuration for auto installation of GPU driver. Structure is [documented below](#nested_gpu_driver_installation_config). + +The `gpu_driver_installation_config` block supports: + +* `gpu_driver_version` (Required) - Mode for how the GPU driver is installed. + Accepted values are: + * `"GPU_DRIVER_VERSION_UNSPECIFIED"`: Default value is to not install any GPU driver. + * `"INSTALLATION_DISABLED"`: Disable GPU driver auto installation and needs manual installation. + * `"DEFAULT"`: "Default" GPU driver in COS and Ubuntu. + * `"LATEST"`: "Latest" GPU driver in COS. + * `gpu_partition_size` (Optional) - Size of partitions to create on the GPU. Valid values are described in the NVIDIA mig [user guide](https://docs.nvidia.com/datacenter/tesla/mig-user-guide/#partitioning). * `gpu_sharing_config` (Optional) - Configuration for GPU sharing. Structure is [documented below](#nested_gpu_sharing_config). diff --git a/mmv1/third_party/terraform/website/docs/r/dataproc_workflow_template.html.markdown b/mmv1/third_party/terraform/website/docs/r/dataproc_workflow_template.html.markdown index 303bda603828..028b6eaabab1 100644 --- a/mmv1/third_party/terraform/website/docs/r/dataproc_workflow_template.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/dataproc_workflow_template.html.markdown @@ -71,700 +71,700 @@ The following arguments are supported: * `jobs` - (Required) Required. The Directed Acyclic Graph of Jobs to submit. - + * `location` - (Required) The location for the resource - + * `name` - (Required) Output only. The resource name of the workflow template, as described in https://cloud.google.com/apis/design/resource_names. * For `projects.regions.workflowTemplates`, the resource name of the template has the following format: `projects/{project_id}/regions/{region}/workflowTemplates/{template_id}` * For `projects.locations.workflowTemplates`, the resource name of the template has the following format: `projects/{project_id}/locations/{location}/workflowTemplates/{template_id}` - + * `placement` - (Required) Required. WorkflowTemplate scheduling information. The `jobs` block supports: - + * `hadoop_job` - (Optional) - Optional. Job is a Hadoop job. - + Job is a Hadoop job. + * `hive_job` - (Optional) - Optional. Job is a Hive job. - + Job is a Hive job. + * `labels` - (Optional) - Optional. The labels to associate with this job. Label keys must be between 1 and 63 characters long, and must conform to the following regular expression: {0,63} No more than 32 labels can be associated with a given job. - + The labels to associate with this job. Label keys must be between 1 and 63 characters long, and must conform to the following regular expression: {0,63} No more than 32 labels can be associated with a given job. + * `pig_job` - (Optional) - Optional. Job is a Pig job. - + Job is a Pig job. + * `prerequisite_step_ids` - (Optional) - Optional. The optional list of prerequisite job step_ids. If not specified, the job will start at the beginning of workflow. - + The optional list of prerequisite job step_ids. If not specified, the job will start at the beginning of workflow. + * `presto_job` - (Optional) - Optional. Job is a Presto job. - + Job is a Presto job. + * `pyspark_job` - (Optional) - Optional. Job is a PySpark job. - + Job is a PySpark job. + * `scheduling` - (Optional) - Optional. Job scheduling configuration. - + Job scheduling configuration. + * `spark_job` - (Optional) - Optional. Job is a Spark job. - + Job is a Spark job. + * `spark_r_job` - (Optional) - Optional. Job is a SparkR job. - + Job is a SparkR job. + * `spark_sql_job` - (Optional) - Optional. Job is a SparkSql job. - + Job is a SparkSql job. + * `step_id` - (Required) Required. The step id. The id must be unique among all jobs within the template. The step id is used as prefix for job id, as job `goog-dataproc-workflow-step-id` label, and in field from other steps. The id must contain only letters (a-z, A-Z), numbers (0-9), underscores (_), and hyphens (-). Cannot begin or end with underscore or hyphen. Must consist of between 3 and 50 characters. - + The `placement` block supports: - + * `cluster_selector` - (Optional) - Optional. A selector that chooses target cluster for jobs based on metadata. The selector is evaluated at the time each job is submitted. - + A selector that chooses target cluster for jobs based on metadata. The selector is evaluated at the time each job is submitted. + * `managed_cluster` - (Optional) A cluster that is managed by the workflow. - + The `config` block supports: - + * `autoscaling_config` - (Optional) - Optional. Autoscaling config for the policy associated with the cluster. Cluster does not autoscale if this field is unset. - + Autoscaling config for the policy associated with the cluster. Cluster does not autoscale if this field is unset. + * `encryption_config` - (Optional) - Optional. Encryption settings for the cluster. - + Encryption settings for the cluster. + * `endpoint_config` - (Optional) - Optional. Port/endpoint configuration for this cluster - + Port/endpoint configuration for this cluster + * `gce_cluster_config` - (Optional) - Optional. The shared Compute Engine config settings for all instances in a cluster. - + The shared Compute Engine config settings for all instances in a cluster. + * `gke_cluster_config` - (Optional) - Optional. The Kubernetes Engine config for Dataproc clusters deployed to Kubernetes. Setting this is considered mutually exclusive with Compute Engine-based options such as `gce_cluster_config`, `master_config`, `worker_config`, `secondary_worker_config`, and `autoscaling_config`. - + The Kubernetes Engine config for Dataproc clusters deployed to Kubernetes. Setting this is considered mutually exclusive with Compute Engine-based options such as `gce_cluster_config`, `master_config`, `worker_config`, `secondary_worker_config`, and `autoscaling_config`. + * `initialization_actions` - (Optional) - Optional. Commands to execute on each node after config is completed. By default, executables are run on master and all worker nodes. You can test a node's `role` metadata to run an executable on a master or worker node, as shown below using `curl` (you can also use `wget`): ROLE=$(curl -H Metadata-Flavor:Google http://metadata/computeMetadata/v1/instance/attributes/dataproc-role) if ; then ... master specific actions ... else ... worker specific actions ... fi - + Commands to execute on each node after config is completed. By default, executables are run on master and all worker nodes. You can test a node's `role` metadata to run an executable on a master or worker node, as shown below using `curl` (you can also use `wget`): ROLE=$(curl -H Metadata-Flavor:Google http://metadata/computeMetadata/v1/instance/attributes/dataproc-role) if ; then ... master specific actions ... else ... worker specific actions ... fi + * `lifecycle_config` - (Optional) - Optional. Lifecycle setting for the cluster. - + Lifecycle setting for the cluster. + * `master_config` - (Optional) - Optional. The Compute Engine config settings for additional worker instances in a cluster. - + The Compute Engine config settings for additional worker instances in a cluster. + * `metastore_config` - (Optional) - Optional. Metastore configuration. - + Metastore configuration. + * `secondary_worker_config` - (Optional) - Optional. The Compute Engine config settings for additional worker instances in a cluster. - + The Compute Engine config settings for additional worker instances in a cluster. + * `security_config` - (Optional) - Optional. Security settings for the cluster. - + Security settings for the cluster. + * `software_config` - (Optional) - Optional. The config settings for software inside the cluster. - + The config settings for software inside the cluster. + * `staging_bucket` - (Optional) - Optional. A Cloud Storage bucket used to stage job dependencies, config files, and job driver console output. If you do not specify a staging bucket, Cloud Dataproc will determine a Cloud Storage location (US, ASIA, or EU) for your cluster's staging bucket according to the Compute Engine zone where your cluster is deployed, and then create and manage this project-level, per-location bucket (see (https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/staging-bucket)). - + A Cloud Storage bucket used to stage job dependencies, config files, and job driver console output. If you do not specify a staging bucket, Cloud Dataproc will determine a Cloud Storage location (US, ASIA, or EU) for your cluster's staging bucket according to the Compute Engine zone where your cluster is deployed, and then create and manage this project-level, per-location bucket (see (https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/staging-bucket)). + * `temp_bucket` - (Optional) - Optional. A Cloud Storage bucket used to store ephemeral cluster and jobs data, such as Spark and MapReduce history files. If you do not specify a temp bucket, Dataproc will determine a Cloud Storage location (US, ASIA, or EU) for your cluster's temp bucket according to the Compute Engine zone where your cluster is deployed, and then create and manage this project-level, per-location bucket. The default bucket has a TTL of 90 days, but you can use any TTL (or none) if you specify a bucket. - + A Cloud Storage bucket used to store ephemeral cluster and jobs data, such as Spark and MapReduce history files. If you do not specify a temp bucket, Dataproc will determine a Cloud Storage location (US, ASIA, or EU) for your cluster's temp bucket according to the Compute Engine zone where your cluster is deployed, and then create and manage this project-level, per-location bucket. The default bucket has a TTL of 90 days, but you can use any TTL (or none) if you specify a bucket. + * `worker_config` - (Optional) - Optional. The Compute Engine config settings for additional worker instances in a cluster. - + The Compute Engine config settings for additional worker instances in a cluster. + - - - * `dag_timeout` - (Optional) (Beta only) Optional. Timeout duration for the DAG of jobs. You can use "s", "m", "h", and "d" suffixes for second, minute, hour, and day duration values, respectively. The timeout duration must be from 10 minutes ("10m") to 24 hours ("24h" or "1d"). The timer begins when the first job is submitted. If the workflow is running at the end of the timeout period, any remaining jobs are cancelled, the workflow is ended, and if the workflow was running on a (/dataproc/docs/concepts/workflows/using-workflows#configuring_or_selecting_a_cluster), the cluster is deleted. - + * `labels` - (Optional) - Optional. The labels to associate with this template. These labels will be propagated to all jobs and clusters created by the workflow instance. Label **keys** must contain 1 to 63 characters, and must conform to (https://www.ietf.org/rfc/rfc1035.txt). No more than 32 labels can be associated with a template. - + The labels to associate with this template. These labels will be propagated to all jobs and clusters created by the workflow instance. Label **keys** must contain 1 to 63 characters, and must conform to (https://www.ietf.org/rfc/rfc1035.txt). No more than 32 labels can be associated with a template. + * `parameters` - (Optional) - Optional. Template parameters whose values are substituted into the template. Values for parameters must be provided when the template is instantiated. - + Template parameters whose values are substituted into the template. Values for parameters must be provided when the template is instantiated. + * `project` - (Optional) The project for the resource - + * `version` - (Optional) - Optional. Used to perform a consistent read-modify-write. This field should be left blank for a `CreateWorkflowTemplate` request. It is required for an `UpdateWorkflowTemplate` request, and must match the current server version. A typical update template flow would fetch the current template with a `GetWorkflowTemplate` request, which will return the current template with the `version` field filled in with the current server version. The user updates other fields in the template, then returns it as part of the `UpdateWorkflowTemplate` request. - + Used to perform a consistent read-modify-write. This field should be left blank for a `CreateWorkflowTemplate` request. It is required for an `UpdateWorkflowTemplate` request, and must match the current server version. A typical update template flow would fetch the current template with a `GetWorkflowTemplate` request, which will return the current template with the `version` field filled in with the current server version. The user updates other fields in the template, then returns it as part of the `UpdateWorkflowTemplate` request. + The `hadoop_job` block supports: - + * `archive_uris` - (Optional) - Optional. HCFS URIs of archives to be extracted in the working directory of Hadoop drivers and tasks. Supported file types: .jar, .tar, .tar.gz, .tgz, or .zip. - + HCFS URIs of archives to be extracted in the working directory of Hadoop drivers and tasks. Supported file types: .jar, .tar, .tar.gz, .tgz, or .zip. + * `args` - (Optional) - Optional. The arguments to pass to the driver. Do not include arguments, such as `-libjars` or `-Dfoo=bar`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. - + The arguments to pass to the driver. Do not include arguments, such as `-libjars` or `-Dfoo=bar`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. + * `file_uris` - (Optional) - Optional. HCFS (Hadoop Compatible Filesystem) URIs of files to be copied to the working directory of Hadoop drivers and distributed tasks. Useful for naively parallel tasks. - + HCFS (Hadoop Compatible Filesystem) URIs of files to be copied to the working directory of Hadoop drivers and distributed tasks. Useful for naively parallel tasks. + * `jar_file_uris` - (Optional) - Optional. Jar file URIs to add to the CLASSPATHs of the Hadoop driver and tasks. - + Jar file URIs to add to the CLASSPATHs of the Hadoop driver and tasks. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `main_class` - (Optional) The name of the driver's main class. The jar file containing the class must be in the default CLASSPATH or specified in `jar_file_uris`. - + * `main_jar_file_uri` - (Optional) The HCFS URI of the jar file containing the main class. Examples: 'gs://foo-bucket/analytics-binaries/extract-useful-metrics-mr.jar' 'hdfs:/tmp/test-samples/custom-wordcount.jar' 'file:///home/usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples.jar' - + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure Hadoop. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site and classes in user code. - + A mapping of property names to values, used to configure Hadoop. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site and classes in user code. + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `hive_job` block supports: - + * `continue_on_failure` - (Optional) - Optional. Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. - + Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. + * `jar_file_uris` - (Optional) - Optional. HCFS URIs of jar files to add to the CLASSPATH of the Hive server and Hadoop MapReduce (MR) tasks. Can contain Hive SerDes and UDFs. - + HCFS URIs of jar files to add to the CLASSPATH of the Hive server and Hadoop MapReduce (MR) tasks. Can contain Hive SerDes and UDFs. + * `properties` - (Optional) - Optional. A mapping of property names and values, used to configure Hive. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site.xml, /etc/hive/conf/hive-site.xml, and classes in user code. - + A mapping of property names and values, used to configure Hive. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site.xml, /etc/hive/conf/hive-site.xml, and classes in user code. + * `query_file_uri` - (Optional) The HCFS URI of the script that contains Hive queries. - + * `query_list` - (Optional) A list of queries. - + * `script_variables` - (Optional) - Optional. Mapping of query variable names to values (equivalent to the Hive command: `SET name="value";`). - + Mapping of query variable names to values (equivalent to the Hive command: `SET name="value";`). + The `query_list` block supports: - + * `queries` - (Required) Required. The queries to execute. You do not need to end a query expression with a semicolon. Multiple queries can be specified in one string by separating each with a semicolon. Here is an example of a Dataproc API snippet that uses a QueryList to specify a HiveJob: "hiveJob": { "queryList": { "queries": } } - + The `pig_job` block supports: - + * `continue_on_failure` - (Optional) - Optional. Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. - + Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. + * `jar_file_uris` - (Optional) - Optional. HCFS URIs of jar files to add to the CLASSPATH of the Pig Client and Hadoop MapReduce (MR) tasks. Can contain Pig UDFs. - + HCFS URIs of jar files to add to the CLASSPATH of the Pig Client and Hadoop MapReduce (MR) tasks. Can contain Pig UDFs. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure Pig. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site.xml, /etc/pig/conf/pig.properties, and classes in user code. - + A mapping of property names to values, used to configure Pig. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/hadoop/conf/*-site.xml, /etc/pig/conf/pig.properties, and classes in user code. + * `query_file_uri` - (Optional) The HCFS URI of the script that contains the Pig queries. - + * `query_list` - (Optional) A list of queries. - + * `script_variables` - (Optional) - Optional. Mapping of query variable names to values (equivalent to the Pig command: `name=`). - + Mapping of query variable names to values (equivalent to the Pig command: `name=`). + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `query_list` block supports: - + * `queries` - (Required) Required. The queries to execute. You do not need to end a query expression with a semicolon. Multiple queries can be specified in one string by separating each with a semicolon. Here is an example of a Dataproc API snippet that uses a QueryList to specify a HiveJob: "hiveJob": { "queryList": { "queries": } } - + The `presto_job` block supports: - + * `client_tags` - (Optional) - Optional. Presto client tags to attach to this query - + Presto client tags to attach to this query + * `continue_on_failure` - (Optional) - Optional. Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. - + Whether to continue executing queries if a query fails. The default value is `false`. Setting to `true` can be useful when executing independent parallel queries. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `output_format` - (Optional) - Optional. The format in which query output will be displayed. See the Presto documentation for supported output formats - + The format in which query output will be displayed. See the Presto documentation for supported output formats + * `properties` - (Optional) - Optional. A mapping of property names to values. Used to set Presto (https://prestodb.io/docs/current/sql/set-session.html) Equivalent to using the --session flag in the Presto CLI - + A mapping of property names to values. Used to set Presto (https://prestodb.io/docs/current/sql/set-session.html) Equivalent to using the --session flag in the Presto CLI + * `query_file_uri` - (Optional) The HCFS URI of the script that contains SQL queries. - + * `query_list` - (Optional) A list of queries. - + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `query_list` block supports: - + * `queries` - (Required) Required. The queries to execute. You do not need to end a query expression with a semicolon. Multiple queries can be specified in one string by separating each with a semicolon. Here is an example of a Dataproc API snippet that uses a QueryList to specify a HiveJob: "hiveJob": { "queryList": { "queries": } } - + The `pyspark_job` block supports: - + * `archive_uris` - (Optional) - Optional. HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. - + HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. + * `args` - (Optional) - Optional. The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. - + The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. + * `file_uris` - (Optional) - Optional. HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. - + HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. + * `jar_file_uris` - (Optional) - Optional. HCFS URIs of jar files to add to the CLASSPATHs of the Python driver and tasks. - + HCFS URIs of jar files to add to the CLASSPATHs of the Python driver and tasks. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `main_python_file_uri` - (Required) Required. The HCFS URI of the main Python file to use as the driver. Must be a .py file. - + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure PySpark. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. - + A mapping of property names to values, used to configure PySpark. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. + * `python_file_uris` - (Optional) - Optional. HCFS file URIs of Python files to pass to the PySpark framework. Supported file types: .py, .egg, and .zip. - + HCFS file URIs of Python files to pass to the PySpark framework. Supported file types: .py, .egg, and .zip. + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `scheduling` block supports: - + * `max_failures_per_hour` - (Optional) - Optional. Maximum number of times per hour a driver may be restarted as a result of driver exiting with non-zero code before job is reported failed. A job may be reported as thrashing if driver exits with non-zero code 4 times within 10 minute window. Maximum value is 10. - + Maximum number of times per hour a driver may be restarted as a result of driver exiting with non-zero code before job is reported failed. A job may be reported as thrashing if driver exits with non-zero code 4 times within 10 minute window. Maximum value is 10. + * `max_failures_total` - (Optional) - Optional. Maximum number of times in total a driver may be restarted as a result of driver exiting with non-zero code before job is reported failed. Maximum value is 240 - + Maximum number of times in total a driver may be restarted as a result of driver exiting with non-zero code before job is reported failed. Maximum value is 240 + The `spark_job` block supports: - + * `archive_uris` - (Optional) - Optional. HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. - + HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. + * `args` - (Optional) - Optional. The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. - + The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. + * `file_uris` - (Optional) - Optional. HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. - + HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. + * `jar_file_uris` - (Optional) - Optional. HCFS URIs of jar files to add to the CLASSPATHs of the Spark driver and tasks. - + HCFS URIs of jar files to add to the CLASSPATHs of the Spark driver and tasks. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `main_class` - (Optional) The name of the driver's main class. The jar file that contains the class must be in the default CLASSPATH or specified in `jar_file_uris`. - + * `main_jar_file_uri` - (Optional) The HCFS URI of the jar file that contains the main class. - + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure Spark. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. - + A mapping of property names to values, used to configure Spark. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `spark_r_job` block supports: - + * `archive_uris` - (Optional) - Optional. HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. - + HCFS URIs of archives to be extracted into the working directory of each executor. Supported file types: .jar, .tar, .tar.gz, .tgz, and .zip. + * `args` - (Optional) - Optional. The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. - + The arguments to pass to the driver. Do not include arguments, such as `--conf`, that can be set as job properties, since a collision may occur that causes an incorrect job submission. + * `file_uris` - (Optional) - Optional. HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. - + HCFS URIs of files to be placed in the working directory of each executor. Useful for naively parallel tasks. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `main_r_file_uri` - (Required) Required. The HCFS URI of the main R file to use as the driver. Must be a .R file. - + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure SparkR. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. - + A mapping of property names to values, used to configure SparkR. Properties that conflict with values set by the Dataproc API may be overwritten. Can include properties set in /etc/spark/conf/spark-defaults.conf and classes in user code. + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `spark_sql_job` block supports: - + * `jar_file_uris` - (Optional) - Optional. HCFS URIs of jar files to be added to the Spark CLASSPATH. - + HCFS URIs of jar files to be added to the Spark CLASSPATH. + * `logging_config` - (Optional) - Optional. The runtime log config for job execution. - + The runtime log config for job execution. + * `properties` - (Optional) - Optional. A mapping of property names to values, used to configure Spark SQL's SparkConf. Properties that conflict with values set by the Dataproc API may be overwritten. - + A mapping of property names to values, used to configure Spark SQL's SparkConf. Properties that conflict with values set by the Dataproc API may be overwritten. + * `query_file_uri` - (Optional) The HCFS URI of the script that contains SQL queries. - + * `query_list` - (Optional) A list of queries. - + * `script_variables` - (Optional) - Optional. Mapping of query variable names to values (equivalent to the Spark SQL command: SET `name="value";`). - + Mapping of query variable names to values (equivalent to the Spark SQL command: SET `name="value";`). + The `logging_config` block supports: - + * `driver_log_levels` - (Optional) The per-package log levels for the driver. This may include "root" package name to configure rootLogger. Examples: 'com.google = FATAL', 'root = INFO', 'org.apache = DEBUG' - + The `query_list` block supports: - + * `queries` - (Required) Required. The queries to execute. You do not need to end a query expression with a semicolon. Multiple queries can be specified in one string by separating each with a semicolon. Here is an example of a Dataproc API snippet that uses a QueryList to specify a HiveJob: "hiveJob": { "queryList": { "queries": } } - + The `parameters` block supports: - + * `description` - (Optional) - Optional. Brief description of the parameter. Must not exceed 1024 characters. - + Brief description of the parameter. Must not exceed 1024 characters. + * `fields` - (Required) Required. Paths to all fields that the parameter replaces. A field is allowed to appear in at most one parameter's list of field paths. A field path is similar in syntax to a .sparkJob.args - + * `name` - (Required) Required. Parameter name. The parameter name is used as the key, and paired with the parameter value, which are passed to the template when the template is instantiated. The name must contain only capital letters (A-Z), numbers (0-9), and underscores (_), and must not start with a number. The maximum length is 40 characters. - + * `validation` - (Optional) - Optional. Validation rules to be applied to this parameter's value. - + Validation rules to be applied to this parameter's value. + The `validation` block supports: - + * `regex` - (Optional) Validation based on regular expressions. - + * `values` - (Optional) Validation based on a list of allowed values. - + The `regex` block supports: - + * `regexes` - (Required) Required. RE2 regular expressions used to validate the parameter's value. The value must match the regex in its entirety (substring matches are not sufficient). - + The `values` block supports: - + * `values` - (Required) Required. List of allowed values for the parameter. - + The `cluster_selector` block supports: - + * `cluster_labels` - (Required) Required. The cluster labels. Cluster must have all labels to match. - + * `zone` - (Optional) - Optional. The zone where workflow process executes. This parameter does not affect the selection of the cluster. If unspecified, the zone of the first cluster matching the selector is used. - + The zone where workflow process executes. This parameter does not affect the selection of the cluster. If unspecified, the zone of the first cluster matching the selector is used. + The `managed_cluster` block supports: - + * `cluster_name` - (Required) Required. The cluster name prefix. A unique cluster name will be formed by appending a random suffix. The name must contain only lower-case letters (a-z), numbers (0-9), and hyphens (-). Must begin with a letter. Cannot begin or end with hyphen. Must consist of between 2 and 35 characters. - + * `config` - (Required) Required. The cluster configuration. - + * `labels` - (Optional) - Optional. The labels to associate with this cluster. Label keys must be between 1 and 63 characters long, and must conform to the following PCRE regular expression: {0,63} No more than 32 labels can be associated with a given cluster. - + The labels to associate with this cluster. Label keys must be between 1 and 63 characters long, and must conform to the following PCRE regular expression: {0,63} No more than 32 labels can be associated with a given cluster. + The `master_config` block supports: - + * `accelerators` - (Optional) - Optional. The Compute Engine accelerator configuration for these instances. - + The Compute Engine accelerator configuration for these instances. + * `disk_config` - (Optional) - Optional. Disk option config settings. - + Disk option config settings. + * `image` - (Optional) - Optional. The Compute Engine image resource used for cluster instances. The URI can represent an image or image family. Image examples: * `https://www.googleapis.com/compute/beta/projects/` If the URI is unspecified, it will be inferred from `SoftwareConfig.image_version` or the system default. - + The Compute Engine image resource used for cluster instances. The URI can represent an image or image family. Image examples: * `https://www.googleapis.com/compute/beta/projects/` If the URI is unspecified, it will be inferred from `SoftwareConfig.image_version` or the system default. + * `machine_type` - (Optional) - Optional. The Compute Engine machine type used for cluster instances. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/(https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/auto-zone#using_auto_zone_placement) feature, you must use the short name of the machine type resource, for example, `n1-standard-2`. - + The Compute Engine machine type used for cluster instances. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/(https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/auto-zone#using_auto_zone_placement) feature, you must use the short name of the machine type resource, for example, `n1-standard-2`. + * `min_cpu_platform` - (Optional) - Optional. Specifies the minimum cpu platform for the Instance Group. See (https://cloud.google.com/dataproc/docs/concepts/compute/dataproc-min-cpu). - + Specifies the minimum cpu platform for the Instance Group. See (https://cloud.google.com/dataproc/docs/concepts/compute/dataproc-min-cpu). + * `num_instances` - (Optional) - Optional. The number of VM instances in the instance group. For master instance groups, must be set to 1. - + The number of VM instances in the instance group. For master instance groups, must be set to 1. + * `preemptibility` - (Optional) - Optional. Specifies the preemptibility of the instance group. The default value for master and worker groups is `NON_PREEMPTIBLE`. This default cannot be changed. The default value for secondary instances is `PREEMPTIBLE`. Possible values: PREEMPTIBILITY_UNSPECIFIED, NON_PREEMPTIBLE, PREEMPTIBLE - + Specifies the preemptibility of the instance group. The default value for master and worker groups is `NON_PREEMPTIBLE`. This default cannot be changed. The default value for secondary instances is `PREEMPTIBLE`. Possible values: PREEMPTIBILITY_UNSPECIFIED, NON_PREEMPTIBLE, PREEMPTIBLE + * `instance_names` - Output only. The list of instance names. Dataproc derives the names from `cluster_name`, `num_instances`, and the instance group. - + * `is_preemptible` - Output only. Specifies that this instance group contains preemptible instances. - + * `managed_group_config` - Output only. The config for Compute Engine Instance Group Manager that manages this group. This is only used for preemptible instance groups. - + The `accelerators` block supports: - + * `accelerator_count` - (Optional) The number of the accelerator cards of this type exposed to this instance. - + * `accelerator_type` - (Optional) Full URL, partial URI, or short name of the accelerator type resource to expose to this instance. See (https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/auto-zone#using_auto_zone_placement) feature, you must use the short name of the accelerator type resource, for example, `nvidia-tesla-k80`. - + The `disk_config` block supports: - + * `boot_disk_size_gb` - (Optional) - Optional. Size in GB of the boot disk (default is 500GB). - + Size in GB of the boot disk (default is 500GB). + * `boot_disk_type` - (Optional) - Optional. Type of the boot disk (default is "pd-standard"). Valid values: "pd-ssd" (Persistent Disk Solid State Drive) or "pd-standard" (Persistent Disk Hard Disk Drive). - + Type of the boot disk (default is "pd-standard"). Valid values: "pd-ssd" (Persistent Disk Solid State Drive) or "pd-standard" (Persistent Disk Hard Disk Drive). + * `num_local_ssds` - (Optional) - Optional. Number of attached SSDs, from 0 to 4 (default is 0). If SSDs are not attached, the boot disk is used to store runtime logs and (https://hadoop.apache.org/docs/r1.2.1/hdfs_user_guide.html) data. If one or more SSDs are attached, this runtime bulk data is spread across them, and the boot disk contains only basic config and installed binaries. - + Number of attached SSDs, from 0 to 4 (default is 0). If SSDs are not attached, the boot disk is used to store runtime logs and (https://hadoop.apache.org/docs/r1.2.1/hdfs_user_guide.html) data. If one or more SSDs are attached, this runtime bulk data is spread across them, and the boot disk contains only basic config and installed binaries. + The `autoscaling_config` block supports: - + * `policy` - (Optional) - Optional. The autoscaling policy used by the cluster. Only resource names including projectid and location (region) are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/` Note that the policy must be in the same project and Dataproc region. - + The autoscaling policy used by the cluster. Only resource names including projectid and location (region) are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/` Note that the policy must be in the same project and Dataproc region. + The `encryption_config` block supports: - + * `gce_pd_kms_key_name` - (Optional) - Optional. The Cloud KMS key name to use for PD disk encryption for all instances in the cluster. - + The Cloud KMS key name to use for PD disk encryption for all instances in the cluster. + The `endpoint_config` block supports: - + * `enable_http_port_access` - (Optional) - Optional. If true, enable http access to specific ports on the cluster from external sources. Defaults to false. - + If true, enable http access to specific ports on the cluster from external sources. Defaults to false. + * `http_ports` - Output only. The map of port descriptions to URLs. Will only be populated if enable_http_port_access is true. - + The `gce_cluster_config` block supports: - + * `internal_ip_only` - (Optional) - Optional. If true, all instances in the cluster will only have internal IP addresses. By default, clusters are not restricted to internal IP addresses, and will have ephemeral external IP addresses assigned to each instance. This `internal_ip_only` restriction can only be enabled for subnetwork enabled networks, and all off-cluster dependencies must be configured to be accessible without external IP addresses. - + If true, all instances in the cluster will only have internal IP addresses. By default, clusters are not restricted to internal IP addresses, and will have ephemeral external IP addresses assigned to each instance. This `internal_ip_only` restriction can only be enabled for subnetwork enabled networks, and all off-cluster dependencies must be configured to be accessible without external IP addresses. + * `metadata` - (Optional) The Compute Engine metadata entries to add to all instances (see (https://cloud.google.com/compute/docs/storing-retrieving-metadata#project_and_instance_metadata)). - + * `network` - (Optional) - Optional. The Compute Engine network to be used for machine communications. Cannot be specified with subnetwork_uri. If neither `network_uri` nor `subnetwork_uri` is specified, the "default" network of the project is used, if it exists. Cannot be a "Custom Subnet Network" (see /regions/global/default` * `default` - + The Compute Engine network to be used for machine communications. Cannot be specified with subnetwork_uri. If neither `network_uri` nor `subnetwork_uri` is specified, the "default" network of the project is used, if it exists. Cannot be a "Custom Subnet Network" (see /regions/global/default` * `default` + * `node_group_affinity` - (Optional) - Optional. Node Group Affinity for sole-tenant clusters. - + Node Group Affinity for sole-tenant clusters. + * `private_ipv6_google_access` - (Optional) - Optional. The type of IPv6 access for a cluster. Possible values: PRIVATE_IPV6_GOOGLE_ACCESS_UNSPECIFIED, INHERIT_FROM_SUBNETWORK, OUTBOUND, BIDIRECTIONAL - + The type of IPv6 access for a cluster. Possible values: PRIVATE_IPV6_GOOGLE_ACCESS_UNSPECIFIED, INHERIT_FROM_SUBNETWORK, OUTBOUND, BIDIRECTIONAL + * `reservation_affinity` - (Optional) - Optional. Reservation Affinity for consuming Zonal reservation. - + Reservation Affinity for consuming Zonal reservation. + * `service_account` - (Optional) - Optional. The (https://cloud.google.com/compute/docs/access/service-accounts#default_service_account) is used. - + The (https://cloud.google.com/compute/docs/access/service-accounts#default_service_account) is used. + * `service_account_scopes` - (Optional) - Optional. The URIs of service account scopes to be included in Compute Engine instances. The following base set of scopes is always included: * https://www.googleapis.com/auth/cloud.useraccounts.readonly * https://www.googleapis.com/auth/devstorage.read_write * https://www.googleapis.com/auth/logging.write If no scopes are specified, the following defaults are also provided: * https://www.googleapis.com/auth/bigquery * https://www.googleapis.com/auth/bigtable.admin.table * https://www.googleapis.com/auth/bigtable.data * https://www.googleapis.com/auth/devstorage.full_control + The URIs of service account scopes to be included in Compute Engine instances. The following base set of scopes is always included: * https://www.googleapis.com/auth/cloud.useraccounts.readonly * https://www.googleapis.com/auth/devstorage.read_write * https://www.googleapis.com/auth/logging.write If no scopes are specified, the following defaults are also provided: * https://www.googleapis.com/auth/bigquery * https://www.googleapis.com/auth/bigtable.admin.table * https://www.googleapis.com/auth/bigtable.data * https://www.googleapis.com/auth/devstorage.full_control * `shielded_instance_config` - (Optional) - Optional. Shielded Instance Config for clusters using [Compute Engine Shielded VMs](https://cloud.google.com/security/shielded-cloud/shielded-vm). Structure [defined below](#nested_shielded_instance_config). - + Shielded Instance Config for clusters using [Compute Engine Shielded VMs](https://cloud.google.com/security/shielded-cloud/shielded-vm). Structure [defined below](#nested_shielded_instance_config). + * `subnetwork` - (Optional) - Optional. The Compute Engine subnetwork to be used for machine communications. Cannot be specified with network_uri. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects//regions/us-east1/subnetworks/sub0` * `sub0` - + The Compute Engine subnetwork to be used for machine communications. Cannot be specified with network_uri. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects//regions/us-east1/subnetworks/sub0` * `sub0` + * `tags` - (Optional) The Compute Engine tags to add to all instances (see (https://cloud.google.com/compute/docs/label-or-tag-resources#tags)). - + * `zone` - (Optional) - Optional. The zone where the Compute Engine cluster will be located. On a create request, it is required in the "global" region. If omitted in a non-global Dataproc region, the service will pick a zone in the corresponding Compute Engine region. On a get request, zone will always be present. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/` * `us-central1-f` - + The zone where the Compute Engine cluster will be located. On a create request, it is required in the "global" region. If omitted in a non-global Dataproc region, the service will pick a zone in the corresponding Compute Engine region. On a get request, zone will always be present. A full URL, partial URI, or short name are valid. Examples: * `https://www.googleapis.com/compute/v1/projects/` * `us-central1-f` + The `node_group_affinity` block supports: - + * `node_group` - (Required) Required. The URI of a sole-tenant /zones/us-central1-a/nodeGroups/node-group-1` * `node-group-1` - + The `reservation_affinity` block supports: - + * `consume_reservation_type` - (Optional) - Optional. Type of reservation to consume Possible values: TYPE_UNSPECIFIED, NO_RESERVATION, ANY_RESERVATION, SPECIFIC_RESERVATION - + Type of reservation to consume Possible values: TYPE_UNSPECIFIED, NO_RESERVATION, ANY_RESERVATION, SPECIFIC_RESERVATION + * `key` - (Optional) - Optional. Corresponds to the label key of reservation resource. - + Corresponds to the label key of reservation resource. + * `values` - (Optional) - Optional. Corresponds to the label values of reservation resource. + Corresponds to the label values of reservation resource. The `shielded_instance_config` block supports: @@ -782,143 +782,162 @@ cluster_config { * `enable_secure_boot` - (Optional) - Optional. Defines whether instances have [Secure Boot](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#secure-boot) enabled. - + Defines whether instances have [Secure Boot](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#secure-boot) enabled. + * `enable_vtpm` - (Optional) - Optional. Defines whether instances have the [vTPM](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#vtpm) enabled. - + Defines whether instances have the [vTPM](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#vtpm) enabled. + * `enable_integrity_monitoring` - (Optional) - Optional. Defines whether instances have [Integrity Monitoring](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#integrity-monitoring) enabled. - + Defines whether instances have [Integrity Monitoring](https://cloud.google.com/compute/shielded-vm/docs/shielded-vm#integrity-monitoring) enabled. + The `gke_cluster_config` block supports: - + * `namespaced_gke_deployment_target` - (Optional) - Optional. A target for the deployment. - + A target for the deployment. + The `namespaced_gke_deployment_target` block supports: - + * `cluster_namespace` - (Optional) - Optional. A namespace within the GKE cluster to deploy into. - + A namespace within the GKE cluster to deploy into. + * `target_gke_cluster` - (Optional) - Optional. The target GKE cluster to deploy to. Format: 'projects/{project}/locations/{location}/clusters/{cluster_id}' - + The target GKE cluster to deploy to. Format: 'projects/{project}/locations/{location}/clusters/{cluster_id}' + The `initialization_actions` block supports: - + * `executable_file` - (Optional) Required. Cloud Storage URI of executable file. - + * `execution_timeout` - (Optional) - Optional. Amount of time executable has to complete. Default is 10 minutes (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). Cluster creation fails with an explanatory error message (the name of the executable that caused the error and the exceeded timeout period) if the executable is not completed at end of the timeout period. - + Amount of time executable has to complete. Default is 10 minutes (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). Cluster creation fails with an explanatory error message (the name of the executable that caused the error and the exceeded timeout period) if the executable is not completed at end of the timeout period. + The `lifecycle_config` block supports: - + * `auto_delete_time` - (Optional) - Optional. The time when cluster will be auto-deleted (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). - + The time when cluster will be auto-deleted (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). + * `auto_delete_ttl` - (Optional) - Optional. The lifetime duration of cluster. The cluster will be auto-deleted at the end of this period. Minimum value is 10 minutes; maximum value is 14 days (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). - + The lifetime duration of cluster. The cluster will be auto-deleted at the end of this period. Minimum value is 10 minutes; maximum value is 14 days (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). + * `idle_delete_ttl` - (Optional) - Optional. The duration to keep the cluster alive while idling (when no jobs are running). Passing this threshold will cause the cluster to be deleted. Minimum value is 5 minutes; maximum value is 14 days (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json). - + The duration to keep the cluster alive while idling (when no jobs are running). Passing this threshold will cause the cluster to be deleted. Minimum value is 5 minutes; maximum value is 14 days (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json). + * `idle_start_time` - Output only. The time when cluster became idle (most recent job finished) and became eligible for deletion due to idleness (see JSON representation of (https://developers.google.com/protocol-buffers/docs/proto3#json)). - + The `metastore_config` block supports: - + * `dataproc_metastore_service` - (Required) Required. Resource name of an existing Dataproc Metastore service. Example: * `projects/` - + The `security_config` block supports: - + * `kerberos_config` - (Optional) Kerberos related configuration. - + The `kerberos_config` block supports: - + * `cross_realm_trust_admin_server` - (Optional) - Optional. The admin server (IP or hostname) for the remote trusted realm in a cross realm trust relationship. - + The admin server (IP or hostname) for the remote trusted realm in a cross realm trust relationship. + * `cross_realm_trust_kdc` - (Optional) - Optional. The KDC (IP or hostname) for the remote trusted realm in a cross realm trust relationship. - + The KDC (IP or hostname) for the remote trusted realm in a cross realm trust relationship. + * `cross_realm_trust_realm` - (Optional) - Optional. The remote realm the Dataproc on-cluster KDC will trust, should the user enable cross realm trust. - + The remote realm the Dataproc on-cluster KDC will trust, should the user enable cross realm trust. + * `cross_realm_trust_shared_password` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the shared password between the on-cluster Kerberos realm and the remote trusted realm, in a cross realm trust relationship. - + The Cloud Storage URI of a KMS encrypted file containing the shared password between the on-cluster Kerberos realm and the remote trusted realm, in a cross realm trust relationship. + * `enable_kerberos` - (Optional) - Optional. Flag to indicate whether to Kerberize the cluster (default: false). Set this field to true to enable Kerberos on a cluster. - + Flag to indicate whether to Kerberize the cluster (default: false). Set this field to true to enable Kerberos on a cluster. + * `kdc_db_key` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the master key of the KDC database. - + The Cloud Storage URI of a KMS encrypted file containing the master key of the KDC database. + * `key_password` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the password to the user provided key. For the self-signed certificate, this password is generated by Dataproc. - + The Cloud Storage URI of a KMS encrypted file containing the password to the user provided key. For the self-signed certificate, this password is generated by Dataproc. + * `keystore` - (Optional) - Optional. The Cloud Storage URI of the keystore file used for SSL encryption. If not provided, Dataproc will provide a self-signed certificate. - + The Cloud Storage URI of the keystore file used for SSL encryption. If not provided, Dataproc will provide a self-signed certificate. + * `keystore_password` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the password to the user provided keystore. For the self-signed certificate, this password is generated by Dataproc. - + The Cloud Storage URI of a KMS encrypted file containing the password to the user provided keystore. For the self-signed certificate, this password is generated by Dataproc. + * `kms_key` - (Optional) - Optional. The uri of the KMS key used to encrypt various sensitive files. - + The uri of the KMS key used to encrypt various sensitive files. + * `realm` - (Optional) - Optional. The name of the on-cluster Kerberos realm. If not specified, the uppercased domain of hostnames will be the realm. - + The name of the on-cluster Kerberos realm. If not specified, the uppercased domain of hostnames will be the realm. + * `root_principal_password` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the root principal password. - + The Cloud Storage URI of a KMS encrypted file containing the root principal password. + * `tgt_lifetime_hours` - (Optional) - Optional. The lifetime of the ticket granting ticket, in hours. If not specified, or user specifies 0, then default value 10 will be used. - + The lifetime of the ticket granting ticket, in hours. If not specified, or user specifies 0, then default value 10 will be used. + * `truststore` - (Optional) - Optional. The Cloud Storage URI of the truststore file used for SSL encryption. If not provided, Dataproc will provide a self-signed certificate. - + The Cloud Storage URI of the truststore file used for SSL encryption. If not provided, Dataproc will provide a self-signed certificate. + * `truststore_password` - (Optional) - Optional. The Cloud Storage URI of a KMS encrypted file containing the password to the user provided truststore. For the self-signed certificate, this password is generated by Dataproc. - + The Cloud Storage URI of a KMS encrypted file containing the password to the user provided truststore. For the self-signed certificate, this password is generated by Dataproc. + The `software_config` block supports: - + * `image_version` - (Optional) - Optional. The version of software inside the cluster. It must be one of the supported (https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-versions#other_versions). If unspecified, it defaults to the latest Debian version. - + The version of software inside the cluster. It must be one of the supported [Dataproc Versions](https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-versions#supported_dataproc_versions), such as "1.2" (including a subminor version, such as "1.2.29"), or the ["preview" version](https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-versions#other_versions). If unspecified, it defaults to the latest Debian version. + +* `optional_components` - + (Optional) + The set of components to activate on the cluster. + * `properties` - (Optional) - Optional. The properties to set on daemon config files. Property keys are specified in `prefix:property` format, for example `core:hadoop.tmp.dir`. The following are supported prefixes and their mappings: * capacity-scheduler: `capacity-scheduler.xml` * core: `core-site.xml` * distcp: `distcp-default.xml` * hdfs: `hdfs-site.xml` * hive: `hive-site.xml` * mapred: `mapred-site.xml` * pig: `pig.properties` * spark: `spark-defaults.conf` * yarn: `yarn-site.xml` For more information, see (https://cloud.google.com/dataproc/docs/concepts/cluster-properties). - + The properties to set on daemon config files. + + Property keys are specified in `prefix:property` format, for example `core:hadoop.tmp.dir`. The following are supported prefixes and their mappings: + + * capacity-scheduler: `capacity-scheduler.xml` + * core: `core-site.xml` + * distcp: `distcp-default.xml` + * hdfs: `hdfs-site.xml` + * hive: `hive-site.xml` + * mapred: `mapred-site.xml` + * pig: `pig.properties` + * spark: `spark-defaults.conf` + * yarn: `yarn-site.xml` + + + For more information, see [Cluster properties](https://cloud.google.com/dataproc/docs/concepts/cluster-properties). + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: @@ -927,10 +946,10 @@ In addition to the arguments listed above, the following computed attributes are * `create_time` - Output only. The time template was created. - + * `update_time` - Output only. The time template was last updated. - + ## Timeouts This resource provides the following diff --git a/mmv1/third_party/terraform/website/docs/r/os_config_os_policy_assignment.html.markdown b/mmv1/third_party/terraform/website/docs/r/os_config_os_policy_assignment.html.markdown index 500aee593ad6..070103344c5f 100644 --- a/mmv1/third_party/terraform/website/docs/r/os_config_os_policy_assignment.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/os_config_os_policy_assignment.html.markdown @@ -1,8 +1,10 @@ -subcategory: "OS Config" description: |- +subcategory: "OS Config" -## OS policy assignment is an API resource that is used to apply a set of OS policies to a dynamically targeted group of Compute Engine VM instances. +description: |- + OS policy assignment is an API resource that is used to apply a set of OS policies to a dynamically targeted group of Compute Engine VM instances. +--- -# google\_os\_config\_os\_policy\_assignment +# google_os_config_os_policy_assignment OS policy assignment is an API resource that is used to apply a set of OS policies to a dynamically targeted group of Compute Engine VM instances. An OS @@ -550,8 +552,7 @@ The following arguments are supported: * `path` - (Required) The absolute path of the file within the VM. * `state` - (Required) Desired state of the file. Possible values are: - `DESIRED_STATE_UNSPECIFIED`, `PRESENT`, `ABSENT`, - `CONTENTS_MATCH`. + `DESIRED_STATE_UNSPECIFIED`, `PRESENT`, `ABSENT`, `CONTENTS_MATCH`. * `permissions` - (Output) Consists of three octal digits which represent, in order, the permissions of the owner, group, and other users for the file diff --git a/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown b/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown index 4ba8f5b721ce..245e5c0a0a99 100644 --- a/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/sql_database_instance.html.markdown @@ -246,9 +246,7 @@ The `settings` block supports: * `edition` - (Optional) The edition of the instance, can be `ENTERPRISE` or `ENTERPRISE_PLUS`. -The optional `settings.advanced_machine_features` subblock supports: - -* `threads_per_core` - (Optional) The number of threads per core. The value of this flag can be 1 or 2. To disable SMT, set this flag to 1. Only available in Cloud SQL for SQL Server instances. See [smt](https://cloud.google.com/sql/docs/sqlserver/create-instance#smt-create-instance) for more details. +* `user_labels` - (Optional) A set of key/value user label pairs to assign to the instance. * `activation_policy` - (Optional) This specifies when the instance should be active. Can be either `ALWAYS`, `NEVER` or `ON_DEMAND`. @@ -278,7 +276,9 @@ The optional `settings.advanced_machine_features` subblock supports: * `time_zone` - (Optional) The time_zone to be used by the database engine (supported only for SQL Server), in SQL Server timezone format. -* `user_labels` - (Optional) A set of key/value user label pairs to assign to the instance. +The optional `settings.advanced_machine_features` subblock supports: + +* `threads_per_core` - (Optional) The number of threads per core. The value of this flag can be 1 or 2. To disable SMT, set this flag to 1. Only available in Cloud SQL for SQL Server instances. See [smt](https://cloud.google.com/sql/docs/sqlserver/create-instance#smt-create-instance) for more details. The optional `settings.database_flags` sublist supports: @@ -434,6 +434,7 @@ to work, cannot be updated, and supports: If the field is set to true the replica will be designated as a failover replica. If the master instance fails, the replica instance will be promoted as the new master instance. + ~> **NOTE:** Not supported for Postgres database. * `master_heartbeat_period` - (Optional) Time in ms between replication heartbeats. diff --git a/mmv1/third_party/validator/tests/data/example_compute_forwarding_rule.json b/mmv1/third_party/validator/tests/data/example_compute_forwarding_rule.json index 62f348e8b0ef..640c524c7183 100644 --- a/mmv1/third_party/validator/tests/data/example_compute_forwarding_rule.json +++ b/mmv1/third_party/validator/tests/data/example_compute_forwarding_rule.json @@ -11,7 +11,7 @@ "data": { "IPProtocol": "TCP", "allowGlobalAccess": false, - "backendService": "https://compute.googleapis.com/compute/v1/projects/{{.Provider.project}}/regions/australia-southeast1/test-backend-service-id", + "backendService": "https://compute.googleapis.com/compute/beta/projects/{{.Provider.project}}/regions/australia-southeast1/test-backend-service-id", "loadBalancingScheme": "INTERNAL_MANAGED", "name": "test-forwarding-rule", "portRange": "80", @@ -19,4 +19,4 @@ } } } -] \ No newline at end of file +] diff --git a/mmv1/third_party/validator/tests/data/example_vpc_access_connector.tf b/mmv1/third_party/validator/tests/data/example_vpc_access_connector.tf index 8e2e45ec0193..e1f7c6f74df6 100644 --- a/mmv1/third_party/validator/tests/data/example_vpc_access_connector.tf +++ b/mmv1/third_party/validator/tests/data/example_vpc_access_connector.tf @@ -27,8 +27,10 @@ provider "google" { } resource "google_vpc_access_connector" "connector" { - name = "vpc-con" - ip_cidr_range = "10.8.0.0/28" - network = "default" - region = "us-central1" + name = "vpc-con" + ip_cidr_range = "10.8.0.0/28" + network = "default" + region = "us-central1" + max_throughput = 300 + min_throughput = 200 } diff --git a/mmv1/third_party/validator/tests/source/iam_test.go.erb b/mmv1/third_party/validator/tests/source/iam_test.go.erb index 1acebfce055e..24722608c892 100644 --- a/mmv1/third_party/validator/tests/source/iam_test.go.erb +++ b/mmv1/third_party/validator/tests/source/iam_test.go.erb @@ -15,7 +15,7 @@ import ( resources "github.com/GoogleCloudPlatform/terraform-google-conversion/v2/tfplan2cai/converters/google/resources" "github.com/GoogleCloudPlatform/terraform-google-conversion/v2/tfplan2cai/tfdata" "github.com/GoogleCloudPlatform/terraform-google-conversion/v2/tfplan2cai/tfplan" - provider "github.com/hashicorp/terraform-provider-google/google" + provider "github.com/hashicorp/terraform-provider-google-beta/google-beta" ) func TestIAMFetchFullResource(t *testing.T) { diff --git a/mmv1/third_party/validator/tests/source/init_test.go b/mmv1/third_party/validator/tests/source/init_test.go index 542bc424229e..8d2910965779 100644 --- a/mmv1/third_party/validator/tests/source/init_test.go +++ b/mmv1/third_party/validator/tests/source/init_test.go @@ -156,6 +156,12 @@ func normalizeAssets(t *testing.T, assets []caiasset.Asset, offline bool) []caia asset.Resource.Data["name"] = re.ReplaceAllString(name, "/placeholder-foobar") } } + // skip comparing version, DiscoveryDocumentURI, + // since switching to beta generates version difference + if asset.Resource != nil { + asset.Resource.Version = "" + asset.Resource.DiscoveryDocumentURI = "" + } ret[i] = asset } return ret diff --git a/tools/breaking-change-detector/constants/constants.go b/tools/breaking-change-detector/constants/constants.go index e41faa4a3a57..b4234432f5d5 100644 --- a/tools/breaking-change-detector/constants/constants.go +++ b/tools/breaking-change-detector/constants/constants.go @@ -1,7 +1,7 @@ package constants -const BreakingChangeRelativeLocation = "develop/" -const BreakingChangeFileName = "breaking-changes" +const BreakingChangeRelativeLocation = "reference/" +const BreakingChangeFileName = "breaking-change-detector" var docsite = "https://googlecloudplatform.github.io/magic-modules/" diff --git a/tools/breaking-change-detector/rules/rule_test.go b/tools/breaking-change-detector/rules/rule_test.go index 78215892ce23..5c2592277e88 100644 --- a/tools/breaking-change-detector/rules/rule_test.go +++ b/tools/breaking-change-detector/rules/rule_test.go @@ -23,7 +23,7 @@ func TestUniqueRuleIdentifiers(t *testing.T) { func TestMarkdownIdentifiers(t *testing.T) { // Define the Markdown file path relative to the importer - mdFilePath := "../../../docs/content/develop/breaking-changes.md" + mdFilePath := "../../../docs/content/reference/breaking-change-detector.md" // Read the Markdown file mdContent, err := ioutil.ReadFile(mdFilePath) diff --git a/tools/issue-labeler/enrolled_teams.yaml b/tools/issue-labeler/enrolled_teams.yaml index e29ef4565eca..acb3e2adcc68 100755 --- a/tools/issue-labeler/enrolled_teams.yaml +++ b/tools/issue-labeler/enrolled_teams.yaml @@ -1,135 +1,135 @@ -services/accesscontextmanager: +service/accesscontextmanager: - google_access_context_manager_ -services/alloydb: +service/alloydb: - google_alloydb_ -services/apigateway: +service/apigateway: - google_api_gateway_ -services/apigee: +service/apigee: - google_apigee_ -services/artifactregistry: +service/artifactregistry: - google_artifact_registry_ -services/beyondcorp: +service/beyondcorp: - google_beyondcorp_ -services/bigquery: +service/bigquery: - google_bigquery_ -services/bigtableadmin: +service/bigtableadmin: - google_bigtable_ -services/billingbudgets: +service/billingbudgets: - google_billing_budget -services/certificatemanager: +service/certificatemanager: - google_certificate_manager_ -services/cloudbilling: +service/cloudbilling: - google_billing_account - google_billing_subaccount -services/cloudbuild: +service/cloudbuild: - google_cloudbuild_ - google_cloudbuildv2_ -services/cloudfunctions: +service/cloudfunctions: - google_cloudfunctions_ - google_cloudfunctions2_ -services/cloudkms: +service/cloudkms: - google_kms_ -services/cloudscheduler: +service/cloudscheduler: - google_cloud_scheduler_ -services/cloudtasks: +service/cloudtasks: - google_cloud_tasks_ -services/composer: +service/composer: - google_composer_ -services/compute-nat: +service/compute-nat: - google_compute_router_nat -services/compute-regional-l7-load-balancer: +service/compute-regional-l7-load-balancer: - google_compute_region_target_http_proxy - google_compute_region_target_https_proxy -services/container: +service/container: - google_container_cluster - google_container_engine_versions - google_container_node_pool -services/dataproc: +service/dataproc: - google_dataproc_cluster - google_dataproc_autoscaling_policy - google_dataproc_job - google_dataproc_workflow_template - google_dataproc_batch -services/dlp: +service/dlp: - google_data_loss_prevention_ -services/edgenetwork: +service/edgenetwork: - google_edgenetwork_ -services/eventarc: +service/eventarc: - google_eventarc_ -services/filestore: +service/filestore: - google_filestore_ -services/firebase: +service/firebase: - google_firebase_ - google_firebaserules_ -services/firestore-controlplane: +service/firestore-controlplane: - google_firestore_database -services/firestore-dataplane: +service/firestore-dataplane: - google_firestore_document - google_firestore_index - google_firestore_ttl -services/gkebackup: +service/gkebackup: - google_gke_backup_ -services/gkehub: +service/gkehub: - google_gke_hub_ -services/gkemulticloud: +service/gkemulticloud: - google_container_aws_ - google_container_azure_ - google_container_attached_ -services/gkeonprem: +service/gkeonprem: - google_gkeonprem_ -services/healthcare: +service/healthcare: - google_healthcare_ -services/iam-core: +service/iam-core: - google_organization_iam_custom_role - google_project_iam_custom_role - google_iam_deny_policy - google_iam_policy - google_iam_role - google_iam_testable_permissions -services/iam-serviceaccount: +service/iam-serviceaccount: - google_service_account -services/iam-wlid: +service/iam-wlid: - google_iam_access_boundary_policy - google_iam_workload_identity_pool - google_iam_workload_identity_pool_provider -services/iam-workforce: +service/iam-workforce: - google_iam_workforce_pool -services/identitytoolkit: +service/identitytoolkit: - google_identity_platform_ -services/ids: +service/ids: - google_cloud_ids_ -services/logging: +service/logging: - google_logging_ -services/looker-core: +service/looker-core: - google_looker_instance -services/monitoring-alerting: +service/monitoring-alerting: - google_monitoring_notification_channel - google_monitoring_alert_policy -services/monitoring-services: +service/monitoring-services: - google_monitoring_custom_service - google_monitoring_dashboard - google_monitoring_monitored_project - google_monitoring_service_ - google_monitoring_slo - google_monitoring_istio_canonical_service -services/orgpolicy: +service/orgpolicy: - google_org_policy_ -services/privateca: +service/privateca: - google_privateca_ -services/pubsublite: +service/pubsublite: - google_pubsub_lite_ -services/redis-instance: +service/redis-instance: - google_redis_instance -services/run: +service/run: - google_cloud_run_ - google_cloud_run_v2_ -services/secretmanager: +service/secretmanager: - google_secret_manager_ -services/spanner: +service/spanner: - google_spanner_ -services/sqladmin: +service/sqladmin: - google_sql_ -services/storage: +service/storage: - google_storage_bucket_ - google_storage_default_object_ - google_storage_hmac_key diff --git a/tools/issue-labeler/labels_test.go b/tools/issue-labeler/labels_test.go index 3e7ae98916eb..0890fb641169 100644 --- a/tools/issue-labeler/labels_test.go +++ b/tools/issue-labeler/labels_test.go @@ -27,7 +27,7 @@ func TestLabels(t *testing.T) { google_gke_hub_feature google_storage_hmac_key #`, - expectedLabels: `["forward/review", "services/gkehub", "services/storage"]`, + expectedLabels: `["forward/review", "service/gkehub", "service/storage"]`, }, { issueBody: `### New or Affected Resource(s): diff --git a/tools/teamcity-generator/go.mod b/tools/teamcity-generator/go.mod new file mode 100644 index 000000000000..e0b2073fc3a3 --- /dev/null +++ b/tools/teamcity-generator/go.mod @@ -0,0 +1,5 @@ +module github.com/GoogleCloudPlatform/magic-modules/tools/teamcity-generator + +go 1.19 + +require golang.org/x/text v0.11.0 diff --git a/tools/teamcity-generator/go.sum b/tools/teamcity-generator/go.sum new file mode 100644 index 000000000000..5f53cd09023b --- /dev/null +++ b/tools/teamcity-generator/go.sum @@ -0,0 +1,2 @@ +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/tools/teamcity-generator/main.go b/tools/teamcity-generator/main.go new file mode 100644 index 000000000000..17e10969d12f --- /dev/null +++ b/tools/teamcity-generator/main.go @@ -0,0 +1,126 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +var GA_VERSION = "ga" +var BETA_VERSION = "beta" + +var oPath = flag.String("output", "", "path to output generated files to") +var ver = flag.String("version", "", "version name, value must be `ga` or `beta`") + +func main() { + var version string + var outputPath string + + flag.Parse() + outputPath = *oPath + version = *ver + if outputPath == "" { + log.Fatalf("missing output flag: provide `--output ` to set the path to output generated files to") + } + if version == "" { + log.Fatalf("missing version flag: provide `--version ` to set the path to output generated files to") + } + if version != GA_VERSION && version != BETA_VERSION { + log.Fatalf("invalid version flag value: value must be `%s` or `%s`", GA_VERSION, BETA_VERSION) + } + + var terraformResourceDirectory string + switch version { + case GA_VERSION: + terraformResourceDirectory = "google" + case BETA_VERSION: + terraformResourceDirectory = "google-beta" + default: + log.Fatalf("invalid version flag value: value must be `%s` or `%s`", GA_VERSION, BETA_VERSION) + } + + log.Printf("Generating TeamCity configuration service package map for `%s` provider", terraformResourceDirectory) + + // Get a list of the service packages found in a given directory + servicesDir := fmt.Sprintf("%s/%s/services", outputPath, terraformResourceDirectory) + serviceList, err := readAllServicePackages(servicesDir) + if err != nil { + log.Fatalf("error determining service package list: %s", err) + } + + // Create a string of the map that should be created in .teamcity/components/generated/services.kt + serviceMap, err := createMap(serviceList) + if err != nil { + log.Fatalf("error creating service package map: %s", err) + } + + // Ensure .teamcity/components/generated/services.kt exists, create if not present + // "Create creates or truncates the named file. If the file already exists, it is truncated." + servicesKtFilePath := fmt.Sprintf("%s/.teamcity/components/generated/services.kt", outputPath) + log.Printf("Opening %s", servicesKtFilePath) + f, err := os.Create(servicesKtFilePath) + if err != nil { + log.Fatalf("error creating or truncating existing file `.teamcity/components/generated/services.kt` in output directory: %s", err) + } + defer f.Close() + + // Save map to .teamcity/components/generated/services.kt + log.Printf("Saving service map to %s", servicesKtFilePath) + _, err = f.Write([]byte(serviceMap)) + if err != nil { + log.Fatalf("error writing to file `.teamcity/components/generated/services.kt` in output directory: %s", err) + } + + log.Println("Finished") +} + +func readAllServicePackages(providerDir string) ([]string, error) { + packages, err := os.ReadDir(providerDir) + if err != nil { + return nil, err + } + var services = make([]string, 0) + + for _, p := range packages { + services = append(services, p.Name()) + } + if len(services) == 0 { + return nil, fmt.Errorf("found 0 service packages in %s", providerDir) + } + return services, nil +} + +func createMap(packageNames []string) (string, error) { + + entryTemplate := " \"%s\" to \"%s\",\n" + lastEntryTemplate := " \"%s\" to \"%s\"\n" // No trailing comma + caser := cases.Title(language.English) + + var b strings.Builder + b.WriteString("// this file is auto-generated by magic-modules/tools/teamcity-generator, any changes made here will be overwritten\n\n") + b.WriteString("var services = mapOf(\n") + for i, p := range packageNames { + + var e string + if i < (len(packageNames) - 1) { + e = fmt.Sprintf(entryTemplate, p, caser.String(p)) + } else { + // Final entry in map doesn't have comma + e = fmt.Sprintf(lastEntryTemplate, p, caser.String(p)) + } + + _, err := fmt.Fprint(&b, e) + if err != nil { + return "", err + } + + } + b.WriteString(")\n") + + return b.String(), nil +} diff --git a/tpgtools/main.go b/tpgtools/main.go index 5afcde3b1b7a..df265cd1721a 100644 --- a/tpgtools/main.go +++ b/tpgtools/main.go @@ -490,7 +490,8 @@ func generateResourceTestFile(res *Resource) { fmt.Printf("%v", string(formatted)) } else { outname := fmt.Sprintf("resource_%s_%s_generated_test.go", res.ProductName(), res.Name()) - err := ioutil.WriteFile(path.Join(*oPath, terraformResourceDirectory, outname), formatted, 0644) + parentDir := getParentDir(res) + err = ioutil.WriteFile(path.Join(parentDir, outname), formatted, 0644) if err != nil { glog.Exit(err) } diff --git a/tpgtools/templates/test_file.go.tmpl b/tpgtools/templates/test_file.go.tmpl index 8fdd0e2120d6..a7db82894dfd 100644 --- a/tpgtools/templates/test_file.go.tmpl +++ b/tpgtools/templates/test_file.go.tmpl @@ -29,7 +29,7 @@ // // ---------------------------------------------------------------------------- -package google +package {{$.Package}}_test import ( "context" @@ -58,15 +58,15 @@ func TestAcc{{$.PathType}}_{{$s.TestSlug}}(t *testing.T) { {{- range $contextkey, $contextvalue := $s.ExpandContext }} "{{$contextkey}}" : {{$contextvalue}}, {{- end }} - "random_suffix": RandString(t, 10), + "random_suffix": acctest.RandString(t, 10), } - VcrTest(t, resource.TestCase{ + acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, {{ if $s.HasGAEquivalent -}} - ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), {{- else }} - ProtoV5ProviderFactories: ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), {{- end }} {{ if true -}} CheckDestroy: testAccCheck{{$.PathType}}DestroyProducer(t), @@ -122,7 +122,7 @@ func testAccCheck{{$.PathType}}DestroyProducer(t *testing.T) func(s *terraform.S continue } - config := GoogleProviderConfig(t) + config := acctest.GoogleProviderConfig(t) billingProject := "" if config.BillingProject != "" {