diff --git a/.ci/containers/build-environment/Dockerfile b/.ci/containers/build-environment/Dockerfile index c342e444e329..b22577e1128a 100644 --- a/.ci/containers/build-environment/Dockerfile +++ b/.ci/containers/build-environment/Dockerfile @@ -23,7 +23,7 @@ RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH" WORKDIR $GOPATH # terraform binary used by tfv/tgc -COPY --from=hashicorp/terraform:1.8.3 /bin/terraform /bin/terraform +COPY --from=hashicorp/terraform:1.10.0 /bin/terraform /bin/terraform SHELL ["/bin/bash", "-c"] diff --git a/.ci/containers/go-plus/Dockerfile b/.ci/containers/go-plus/Dockerfile index 550729cb2681..fb4099144554 100644 --- a/.ci/containers/go-plus/Dockerfile +++ b/.ci/containers/go-plus/Dockerfile @@ -29,7 +29,7 @@ RUN apt-get update && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -RUN wget https://releases.hashicorp.com/terraform/1.8.3/terraform_1.8.3_linux_amd64.zip \ - && unzip terraform_1.8.3_linux_amd64.zip \ - && rm terraform_1.8.3_linux_amd64.zip \ +RUN wget https://releases.hashicorp.com/terraform/1.10.0/terraform_1.10.0_linux_amd64.zip \ + && unzip terraform_1.10.0_linux_amd64.zip \ + && rm terraform_1.10.0_linux_amd64.zip \ && mv ./terraform /bin/terraform diff --git a/.ci/gcb-generate-diffs-new.yml b/.ci/gcb-generate-diffs-new.yml deleted file mode 100644 index feaff16211ae..000000000000 --- a/.ci/gcb-generate-diffs-new.yml +++ /dev/null @@ -1,330 +0,0 @@ ---- -steps: - - name: 'gcr.io/cloud-builders/gcloud' - id: "Stop Other Ongoing Build" - entrypoint: 'bash' - args: - - -c - - | - on_going_build=($(gcloud builds list --ongoing --format='value[separator=","](id,substitutions.REVISION_ID)' --filter="substitutions.TRIGGER_NAME:$TRIGGER_NAME substitutions._PR_NUMBER:$_PR_NUMBER" | xargs)) - for (( i=0; i<${#on_going_build[@]}; i++ )); do - IFS="," read -r -a fields <<< "${on_going_build[i]}" - if [ "$i" -gt "0" ] && [ "${fields[1]}" != $COMMIT_SHA ]; then # skip current - echo "Cancelling build ${fields[0]}" - - gcloud builds cancel ${fields[0]} - fi - done - - # The GCB / GH integration uses a shallow clone of the repo. We need to convert - # that to a full clone in order to work with it properly. - # https://cloud.google.com/source-repositories/docs/integrating-with-cloud-build#unshallowing_clones - - name: 'gcr.io/cloud-builders/git' - args: - - fetch - - --unshallow - # We need to configure git since creating the merge commit is - # technically a commit. - - name: 'gcr.io/cloud-builders/git' - args: - - config - - --global - - user.email - - magic-modules+differ@google.com - - name: 'gcr.io/cloud-builders/git' - args: - - config - - --global - - user.name - - "Modular Magician Diff Process" - # Then we check out the branch provided, and merge it into - # the base branch provided. This matches the behavior - # we're used to from Concourse. - - name: 'gcr.io/cloud-builders/git' - args: - - remote - - add - - head - - $_HEAD_REPO_URL - - - name: 'gcr.io/cloud-builders/git' - args: - - fetch - - head - - $_HEAD_BRANCH - - - name: 'gcr.io/cloud-builders/git' - args: - - checkout - - origin/$_BASE_BRANCH - - name: 'gcr.io/cloud-builders/git' - id: merged - args: - - merge - - --no-ff - - head/$_HEAD_BRANCH - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: build-magician-binary - waitFor: ["merged"] - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: remove-label - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'remove-label' - - $_PR_NUMBER - - 'awaiting-approval' - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tpg-head - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'head' - - 'terraform' - - 'ga' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tpg-base - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'base' - - 'terraform' - - 'ga' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - id: tpgb-head - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'head' - - 'terraform' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tpgb-base - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'base' - - 'terraform' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tgc-head - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'head' - - 'terraform-google-conversion' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tgc-base - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'base' - - 'terraform-google-conversion' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tf-oics-head - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'head' - - 'tf-oics' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/build-environment' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: tf-oics-base - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS"] - waitFor: ["build-magician-binary"] - env: - - BASE_BRANCH=$_BASE_BRANCH - args: - - 'generate-downstream' - - 'base' - - 'tf-oics' - - 'beta' - - $_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/go-plus' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - id: diff - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS", "GITHUB_TOKEN_MAGIC_MODULES"] - args: - - 'generate-comment' - env: - - BUILD_ID=$BUILD_ID - - PROJECT_ID=$PROJECT_ID - - BUILD_STEP=17 - - COMMIT_SHA=$COMMIT_SHA - - PR_NUMBER=$_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/go-plus' - id: tgc-test - allowFailure: true - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["tpgb-head", "tpgb-base", "tgc-head", "tgc-base"] - args: - - 'test-tgc' - env: - - COMMIT_SHA=$COMMIT_SHA - - PR_NUMBER=$_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/go-plus' - id: tgc-test-integration - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - allowFailure: true - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["tpgb-head", "tpgb-base", "tgc-head", "tgc-base"] - env: - - TEST_PROJECT=$_VALIDATOR_TEST_PROJECT - - TEST_FOLDER_ID=$_VALIDATOR_TEST_FOLDER - - TEST_ANCESTRY=$_VALIDATOR_TEST_ANCESTRY - - TEST_ORG_ID=$_VALIDATOR_TEST_ORG - args: - - 'test-tgc-integration' - - $_PR_NUMBER - - $COMMIT_SHA - - $BUILD_ID - - $PROJECT_ID - - "18" # Build step - - terraform-google-conversion - - - name: 'gcr.io/graphite-docker-images/go-plus' - id: tpgb-test - allowFailure: true - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["tpgb-head", "tpgb-base"] - args: - - 'test-tpg' - env: - - VERSION=beta - - COMMIT_SHA=$COMMIT_SHA - - PR_NUMBER=$_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/go-plus' - id: tpg-test - allowFailure: true - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["tpg-head", "tpg-base"] - args: - - 'test-tpg' - env: - - VERSION=ga - - COMMIT_SHA=$COMMIT_SHA - - PR_NUMBER=$_PR_NUMBER - - - name: 'gcr.io/graphite-docker-images/go-plus' - id: gcb-tpg-vcr-test - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_DOWNSTREAMS", "GITHUB_TOKEN_MAGIC_MODULES", "GOOGLE_BILLING_ACCOUNT", "GOOGLE_CUST_ID", "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 - - "GOOGLE_REGION=us-central1" - - "GOOGLE_ZONE=us-central1-a" - - "USER=magician" - args: - - 'test-terraform-vcr' - - $_PR_NUMBER - - $COMMIT_SHA - - $BUILD_ID - - $PROJECT_ID - - "22" # Build step - - - name: 'gcr.io/graphite-docker-images/go-plus' - entrypoint: '/workspace/.ci/scripts/go-plus/magician/exec.sh' - secretEnv: ["GITHUB_TOKEN_MAGIC_MODULES"] - waitFor: ["diff"] - args: - - 'request-service-reviewers' - - $_PR_NUMBER - env: - - COMMIT_SHA=$COMMIT_SHA - -# Long timeout to enable waiting on VCR test -timeout: 64800s -options: - machineType: 'N1_HIGHCPU_32' - -logsBucket: 'gs://cloudbuild-generate-diffs-logs' -availableSecrets: - secretManager: - - versionName: projects/673497134629/secrets/github-magician-token-generate-diffs-downstreams/versions/latest - env: GITHUB_TOKEN_DOWNSTREAMS - - versionName: projects/673497134629/secrets/github-magician-token-generate-diffs-magic-modules/versions/latest - env: GITHUB_TOKEN_MAGIC_MODULES - - versionName: projects/673497134629/secrets/ci-test-billing-account/versions/latest - env: GOOGLE_BILLING_ACCOUNT - - versionName: projects/673497134629/secrets/ci-test-cust-id/versions/latest - env: GOOGLE_CUST_ID - - versionName: projects/673497134629/secrets/ci-test-identity-user/versions/latest - env: GOOGLE_IDENTITY_USER - - versionName: projects/673497134629/secrets/ci-test-master-billing-account/versions/latest - env: GOOGLE_MASTER_BILLING_ACCOUNT - - versionName: projects/673497134629/secrets/ci-test-org/versions/latest - env: GOOGLE_ORG - - versionName: projects/673497134629/secrets/ci-test-org-2/versions/latest - env: GOOGLE_ORG_2 - - versionName: projects/673497134629/secrets/ci-test-org-domain/versions/latest - env: GOOGLE_ORG_DOMAIN - - versionName: projects/673497134629/secrets/ci-test-project/versions/latest - env: GOOGLE_PROJECT - - versionName: projects/673497134629/secrets/ci-test-project-number/versions/latest - env: GOOGLE_PROJECT_NUMBER - - versionName: projects/673497134629/secrets/ci-test-service-account/versions/latest - env: GOOGLE_SERVICE_ACCOUNT - - versionName: projects/673497134629/secrets/ci-test-service-account-key/versions/latest - env: SA_KEY - - versionName: projects/673497134629/secrets/ci-test-public-advertised-prefix-description/versions/latest - env: GOOGLE_PUBLIC_AVERTISED_PREFIX_DESCRIPTION diff --git a/.ci/gcb-pr-downstream-generation-and-test.yml b/.ci/gcb-pr-downstream-generation-and-test.yml index 9e753b8d5174..ea47186f1a25 100644 --- a/.ci/gcb-pr-downstream-generation-and-test.yml +++ b/.ci/gcb-pr-downstream-generation-and-test.yml @@ -277,7 +277,7 @@ steps: - COMMIT_SHA=$COMMIT_SHA # Long timeout to enable waiting on VCR test -timeout: 20000s +timeout: 64800s options: machineType: 'N1_HIGHCPU_32' diff --git a/.ci/magician/cmd/generate_downstream.go b/.ci/magician/cmd/generate_downstream.go index 5a056dafef55..c1dbd2ee9817 100644 --- a/.ci/magician/cmd/generate_downstream.go +++ b/.ci/magician/cmd/generate_downstream.go @@ -335,12 +335,15 @@ func createCommit(scratchRepo *source.Repo, commitMessage string, rnr ExecRunner commitSha = strings.TrimSpace(commitSha) fmt.Printf("Commit sha on the branch is: `%s`\n", commitSha) - variablePath := fmt.Sprintf("/workspace/commitSHA_modular-magician_%s.txt", scratchRepo.Name) - fmt.Println("variablePath: ", variablePath) - - err = rnr.WriteFile(variablePath, commitSha) - if err != nil { - fmt.Println("Error:", err) + // auto-pr's use commitSHA_modular-magician__.txt file to communicate commmit hash + // across cloudbuild steps. Used in test-tpg to execute unit tests for the HEAD commit + if strings.HasPrefix(scratchRepo.Branch, "auto-pr-") && !strings.HasSuffix(scratchRepo.Branch, "-old") { + variablePath := fmt.Sprintf("/workspace/commitSHA_modular-magician_%s.txt", scratchRepo.Name) + fmt.Println("variablePath: ", variablePath) + err = rnr.WriteFile(variablePath, commitSha) + if err != nil { + fmt.Println("Error:", err) + } } return commitSha, err diff --git a/.ci/magician/cmd/interfaces.go b/.ci/magician/cmd/interfaces.go index 71f0f05218e8..61219ef38472 100644 --- a/.ci/magician/cmd/interfaces.go +++ b/.ci/magician/cmd/interfaces.go @@ -48,6 +48,7 @@ type ExecRunner interface { RemoveAll(path string) error PushDir(path string) error PopDir() error + ReadFile(name string) (string, error) WriteFile(name, data string) error AppendFile(name, data string) error // Not used (yet). Run(name string, args []string, env map[string]string) (string, error) diff --git a/.ci/magician/cmd/scheduled_pr_reminders.go b/.ci/magician/cmd/scheduled_pr_reminders.go index 884b494c806a..f918fd547456 100644 --- a/.ci/magician/cmd/scheduled_pr_reminders.go +++ b/.ci/magician/cmd/scheduled_pr_reminders.go @@ -267,29 +267,20 @@ func (s pullRequestReviewState) String() string { // We don't specially handle cases where the contributor has "acted" because it would be // significant additional effort, and this case is already handled by re-requesting review // automatically based on contributor actions. -func notificationState(pr *github.PullRequest, issueEvents []*github.IssueEvent, reviews []*github.PullRequestReview) (pullRequestReviewState, time.Time, error) { - slices.SortFunc(issueEvents, func(a, b *github.IssueEvent) int { - if a.CreatedAt.Before(*b.CreatedAt.GetTime()) { - return 1 +func notificationState(pr *github.PullRequest, issueEventsDesc []*github.IssueEvent, reviewsDesc []*github.PullRequestReview) (pullRequestReviewState, time.Time, error) { + issueEventsDesc = sortedEventsDesc(issueEventsDesc) + reviewsDesc = sortedReviewsDesc(reviewsDesc) + + var readyForReviewTime = *pr.CreatedAt.GetTime() + for _, event := range issueEventsDesc { + if "ready_for_review" == *event.Event { + readyForReviewTime = maxTime(*event.CreatedAt.GetTime(), readyForReviewTime) } - if a.CreatedAt.After(*b.CreatedAt.GetTime()) { - return -1 - } - return 0 - }) - slices.SortFunc(reviews, func(a, b *github.PullRequestReview) int { - if a.SubmittedAt.Before(*b.SubmittedAt.GetTime()) { - return 1 - } - if a.SubmittedAt.After(*b.SubmittedAt.GetTime()) { - return -1 - } - return 0 - }) + } var latestReviewRequest *github.IssueEvent removedRequests := map[string]struct{}{} - for _, event := range issueEvents { + for _, event := range issueEventsDesc { if *event.Event == "review_request_removed" && event.RequestedReviewer != nil { removedRequests[*event.RequestedReviewer.Login] = struct{}{} continue @@ -320,7 +311,7 @@ func notificationState(pr *github.PullRequest, issueEvents []*github.IssueEvent, var earliestCommented *github.PullRequestReview ignoreBy := map[string]struct{}{} - for _, review := range reviews { + for _, review := range reviewsDesc { if review.SubmittedAt.Before(*latestReviewRequest.CreatedAt.GetTime()) { break } @@ -355,15 +346,59 @@ func notificationState(pr *github.PullRequest, issueEvents []*github.IssueEvent, } if earliestChangesRequested != nil { - return waitingForContributor, *earliestChangesRequested.SubmittedAt.GetTime(), nil + timeState := maxTime(*earliestChangesRequested.SubmittedAt.GetTime(), readyForReviewTime) + return waitingForContributor, timeState, nil } if earliestApproved != nil { - return waitingForMerge, *earliestApproved.SubmittedAt.GetTime(), nil + timeState := maxTime(*earliestApproved.SubmittedAt.GetTime(), readyForReviewTime) + return waitingForMerge, timeState, nil } if earliestCommented != nil { - return waitingForContributor, *earliestCommented.SubmittedAt.GetTime(), nil + timeState := maxTime(*earliestCommented.SubmittedAt.GetTime(), readyForReviewTime) + return waitingForContributor, timeState, nil + } + timeState := maxTime(*latestReviewRequest.CreatedAt.GetTime(), readyForReviewTime) + return waitingForReview, timeState, nil +} + +// compareTimeDesc returns sort ordering for descending time comparison (newest first) +func compareTimeDesc(a, b time.Time) int { + if a.Before(b) { + return 1 + } + if a.After(b) { + return -1 + } + return 0 +} + +// sortedEventsDesc returns events sorted by creation time, newest first +func sortedEventsDesc(events []*github.IssueEvent) []*github.IssueEvent { + sortedEvents := make([]*github.IssueEvent, len(events)) + copy(sortedEvents, events) + slices.SortFunc(sortedEvents, func(a, b *github.IssueEvent) int { + return compareTimeDesc(*a.CreatedAt.GetTime(), *b.CreatedAt.GetTime()) + }) + return sortedEvents +} + +// sortedReviewsDesc returns reviews sorted by submission time, newest first +func sortedReviewsDesc(reviews []*github.PullRequestReview) []*github.PullRequestReview { + sortedReviews := make([]*github.PullRequestReview, len(reviews)) + copy(sortedReviews, reviews) + slices.SortFunc(sortedReviews, func(a, b *github.PullRequestReview) int { + return compareTimeDesc(*a.SubmittedAt.GetTime(), *b.SubmittedAt.GetTime()) + }) + return sortedReviews +} + +// maxTime - returns whichever time occured after the other +func maxTime(time1, time2 time.Time) time.Time { + // Return the later time + if time1.After(time2) { + return time1 } - return waitingForReview, *latestReviewRequest.CreatedAt.GetTime(), nil + return time2 } // Calculates the number of PDT days between from and to (by calendar date, not # of hours). diff --git a/.ci/magician/cmd/scheduled_pr_reminders_test.go b/.ci/magician/cmd/scheduled_pr_reminders_test.go index 1777130cc623..b2556f42aac5 100644 --- a/.ci/magician/cmd/scheduled_pr_reminders_test.go +++ b/.ci/magician/cmd/scheduled_pr_reminders_test.go @@ -11,8 +11,9 @@ import ( ) func TestNotificationState(t *testing.T) { - firstCoreReviewer := membership.AvailableReviewers()[0] - secondCoreReviewer := membership.AvailableReviewers()[1] + availableReviewers := membership.AvailableReviewers() + firstCoreReviewer := availableReviewers[0] + secondCoreReviewer := availableReviewers[1] cases := map[string]struct { pullRequest *github.PullRequest issueEvents []*github.IssueEvent @@ -442,6 +443,183 @@ func TestNotificationState(t *testing.T) { expectState: waitingForMerge, expectSince: time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC), }, + "ready_for_review event after creation": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + }, + }, + expectState: waitingForReview, + expectSince: time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC), + }, + + "ready_for_review event before review request": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + }, + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + }, + expectState: waitingForReview, + expectSince: time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC), + }, + + "review after ready_for_review": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + }, + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + }, + reviews: []*github.PullRequestReview{ + &github.PullRequestReview{ + User: &github.User{Login: github.String(firstCoreReviewer)}, + State: github.String("APPROVED"), + SubmittedAt: &github.Timestamp{time.Date(2024, 1, 4, 0, 0, 0, 0, time.UTC)}, + }, + }, + expectState: waitingForMerge, + expectSince: time.Date(2024, 1, 4, 0, 0, 0, 0, time.UTC), + }, + "changes_requested after ready_for_review": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, // Earlier request + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + }, + }, + reviews: []*github.PullRequestReview{ + &github.PullRequestReview{ + User: &github.User{Login: github.String(firstCoreReviewer)}, + State: github.String("CHANGES_REQUESTED"), + SubmittedAt: &github.Timestamp{time.Date(2024, 1, 4, 0, 0, 0, 0, time.UTC)}, // Early changes requested + }, + }, + expectState: waitingForContributor, + expectSince: time.Date(2024, 1, 4, 0, 0, 0, 0, time.UTC), // Should use ready_for_review time + }, + + "changes_requested before ready_for_review": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, // Earlier ready + }, + }, + reviews: []*github.PullRequestReview{ + &github.PullRequestReview{ + User: &github.User{Login: github.String(firstCoreReviewer)}, + State: github.String("CHANGES_REQUESTED"), + SubmittedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + }, + }, + expectState: waitingForContributor, + expectSince: time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC), // Should use changes requested time since it's later + }, + + "comment review after ready_for_review": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + }, + reviews: []*github.PullRequestReview{ + &github.PullRequestReview{ + User: &github.User{Login: github.String(firstCoreReviewer)}, + State: github.String("COMMENTED"), + SubmittedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + }, + }, + expectState: waitingForContributor, + expectSince: time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC), // Should use ready_for_review time + }, + + "multiple ready_for_review events": { + pullRequest: &github.PullRequest{ + User: &github.User{Login: github.String("author")}, + CreatedAt: &github.Timestamp{time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + issueEvents: []*github.IssueEvent{ + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)}, + }, + &github.IssueEvent{ + Event: github.String("review_requested"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 3, 0, 0, 0, 0, time.UTC)}, + RequestedReviewer: &github.User{Login: github.String(firstCoreReviewer)}, + }, + &github.IssueEvent{ + Event: github.String("ready_for_review"), + CreatedAt: &github.Timestamp{time.Date(2024, 1, 5, 0, 0, 0, 0, time.UTC)}, // Later ready_for_review + }, + }, + reviews: []*github.PullRequestReview{ + &github.PullRequestReview{ + User: &github.User{Login: github.String(firstCoreReviewer)}, + State: github.String("CHANGES_REQUESTED"), + SubmittedAt: &github.Timestamp{time.Date(2024, 1, 4, 0, 0, 0, 0, time.UTC)}, + }, + }, + expectState: waitingForContributor, + expectSince: time.Date(2024, 1, 5, 0, 0, 0, 0, time.UTC), // Should use latest ready_for_review time + }, } for tn, tc := range cases { @@ -786,8 +964,9 @@ func TestShouldNotify(t *testing.T) { } func TestFormatReminderComment(t *testing.T) { - firstCoreReviewer := membership.AvailableReviewers()[0] - secondCoreReviewer := membership.AvailableReviewers()[1] + availableReviewers := membership.AvailableReviewers() + firstCoreReviewer := availableReviewers[0] + secondCoreReviewer := availableReviewers[1] cases := map[string]struct { pullRequest *github.PullRequest state pullRequestReviewState diff --git a/.ci/magician/cmd/templates/vcr/with_replay_failed_tests.tmpl b/.ci/magician/cmd/templates/vcr/with_replay_failed_tests.tmpl index 68c804f67584..d6d14bb4175f 100644 --- a/.ci/magician/cmd/templates/vcr/with_replay_failed_tests.tmpl +++ b/.ci/magician/cmd/templates/vcr/with_replay_failed_tests.tmpl @@ -9,4 +9,4 @@ -[Get to know how VCR tests work](https://googlecloudplatform.github.io/magic-modules/docs/getting-started/contributing/#general-contributing-steps) +[Get to know how VCR tests work](https://googlecloudplatform.github.io/magic-modules/develop/test/test/) diff --git a/.ci/magician/cmd/test_eap_vcr.go b/.ci/magician/cmd/test_eap_vcr.go index 06419e6b23eb..8c8c1ce863e1 100644 --- a/.ci/magician/cmd/test_eap_vcr.go +++ b/.ci/magician/cmd/test_eap_vcr.go @@ -104,9 +104,9 @@ func execTestEAPVCR(changeNumber, genPath, kokoroArtifactsDir, modifiedFilePath return fmt.Errorf("error changing to gen path: %w", err) } - changedFiles, err := rnr.Run("git", []string{"diff", "--name-only"}, nil) + changedFiles, err := rnr.ReadFile("diff.log") if err != nil { - return fmt.Errorf("error diffing gen path: %w", err) + return fmt.Errorf("error reading diff log: %w", err) } services, runFullVCR := modifiedPackages(strings.Split(changedFiles, "\n"), provider.Private) diff --git a/.ci/magician/cmd/test_terraform_vcr_test.go b/.ci/magician/cmd/test_terraform_vcr_test.go index 79672641c07f..cf7e4b019327 100644 --- a/.ci/magician/cmd/test_terraform_vcr_test.go +++ b/.ci/magician/cmd/test_terraform_vcr_test.go @@ -447,7 +447,7 @@ func TestWithReplayFailedTests(t *testing.T) { "", "", "", - "[Get to know how VCR tests work](https://googlecloudplatform.github.io/magic-modules/docs/getting-started/contributing/#general-contributing-steps)", + "[Get to know how VCR tests work](https://googlecloudplatform.github.io/magic-modules/develop/test/test/)", }, "\n", ), diff --git a/.ci/magician/cmd/vcr_merge_eap.go b/.ci/magician/cmd/vcr_merge_eap.go new file mode 100644 index 000000000000..5797f0aaf52d --- /dev/null +++ b/.ci/magician/cmd/vcr_merge_eap.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "fmt" + "magician/exec" + "magician/github" + "magician/source" + "os" + + "github.com/spf13/cobra" +) + +var vcrMergeEapCmd = &cobra.Command{ + Use: "vcr-merge-eap", + Short: "Merge VCR cassettes for EAP", + Long: `This command is triggered in .ci/gcb-push-downstream.yml to merge vcr cassettes. + + The command expects the following as arguments: + 1. CL number + + It then performs the following operations: + 1. Run gsutil to list, copy, and remove the vcr cassettes fixtures. + `, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clNumber := args[0] + fmt.Println("CL number:", clNumber) + + githubToken, ok := os.LookupEnv("GITHUB_TOKEN_CLASSIC") + if !ok { + return fmt.Errorf("did not provide GITHUB_TOKEN_CLASSIC environment variable") + } + + baseBranch := os.Getenv("BASE_BRANCH") + if baseBranch == "" { + return fmt.Errorf("environment variable BASE_BRANCH is empty") + } + + rnr, err := exec.NewRunner() + if err != nil { + return fmt.Errorf("error creating Runner: %w", err) + } + + gh := github.NewClient(githubToken) + return execVCRMergeEAP(gh, clNumber, baseBranch, rnr) + }, +} + +func execVCRMergeEAP(gh GithubClient, clNumber, baseBranch string, runner source.Runner) error { + head := "auto-cl-" + clNumber + mergeCassettes("gs://ci-vcr-cassettes/private", baseBranch, fmt.Sprintf("refs/heads/%s", head), runner) + return nil +} + +func init() { + rootCmd.AddCommand(vcrMergeEapCmd) +} diff --git a/.ci/magician/github/membership_data.go b/.ci/magician/github/membership_data.go index 5b0bba634f60..23043482634c 100644 --- a/.ci/magician/github/membership_data.go +++ b/.ci/magician/github/membership_data.go @@ -11,7 +11,6 @@ var ( "melinath": {}, "ScottSuarez": {}, "shuyama1": {}, - "SarahFrench": {}, "roaks3": {}, "zli82016": {}, "trodge": {}, @@ -58,8 +57,8 @@ var ( }, { id: "melinath", - startDate: newDate(2024, 9, 18, pdtLoc), - endDate: newDate(2024, 9, 23, pdtLoc), + startDate: newDate(2024, 12, 19, pdtLoc), + endDate: newDate(2025, 1, 7, pdtLoc), }, { id: "slevenick", @@ -88,19 +87,14 @@ var ( }, { id: "trodge", - startDate: newDate(2024, 10, 23, pdtLoc), - endDate: newDate(2024, 10, 25, pdtLoc), + startDate: newDate(2024, 12, 5, pdtLoc), + endDate: newDate(2024, 12, 8, pdtLoc), }, { id: "roaks3", startDate: newDate(2024, 9, 13, pdtLoc), endDate: newDate(2024, 9, 20, pdtLoc), }, - { - id: "SarahFrench", - startDate: newDate(2024, 11, 15, bstLoc), - endDate: newDate(2024, 12, 2, bstLoc), - }, { id: "c2thorn", startDate: newDate(2024, 10, 2, bstLoc), @@ -121,5 +115,15 @@ var ( startDate: newDate(2024, 11, 26, pdtLoc), endDate: newDate(2024, 12, 4, pdtLoc), }, + { + id: "c2thorn", + startDate: newDate(2024, 11, 27, pdtLoc), + endDate: newDate(2024, 12, 9, pdtLoc), + }, + { + id: "roaks3", + startDate: newDate(2024, 12, 6, pdtLoc), + endDate: newDate(2024, 12, 8, pdtLoc), + }, } ) diff --git a/.ci/magician/go.mod b/.ci/magician/go.mod index e3443c66892b..61ce18c80238 100644 --- a/.ci/magician/go.mod +++ b/.ci/magician/go.mod @@ -7,7 +7,7 @@ replace github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler => ../. require ( github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler v0.0.0-00010101000000-000000000000 github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 // indirect golang.org/x/exp v0.0.0-20230810033253-352e893a4cad google.golang.org/api v0.114.0 diff --git a/.ci/magician/go.sum b/.ci/magician/go.sum index 041a2fb36447..ec29a418f5c0 100644 --- a/.ci/magician/go.sum +++ b/.ci/magician/go.sum @@ -10,7 +10,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -77,8 +77,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/.github/workflows/request-reviewer.yml b/.github/workflows/request-reviewer.yml index 03dbbb2b9afa..4b913b5c3911 100644 --- a/.github/workflows/request-reviewer.yml +++ b/.github/workflows/request-reviewer.yml @@ -15,7 +15,7 @@ on: jobs: request-review: - if: (github.event.action == 'created' && github.event.issue.draft == false && github.event.comment.user.login == github.event.issue.user.login) || (github.event.action != 'created' && github.event.pull_request.draft == false) + if: (github.event.action == 'created' && github.event.issue.state == 'open' && github.event.issue.draft == false && github.event.comment.user.login == github.event.issue.user.login) || (github.event.action != 'created' && github.event.pull_request.state == 'open' && github.event.pull_request.draft == false ) runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/.github/workflows/teamcity-services-diff-check-weekly.yml b/.github/workflows/teamcity-services-diff-check-weekly.yml index d9c257b1aca6..877c98844bfb 100644 --- a/.github/workflows/teamcity-services-diff-check-weekly.yml +++ b/.github/workflows/teamcity-services-diff-check-weekly.yml @@ -37,11 +37,13 @@ jobs: run: echo "GOOGLE_BETA_REPO_PATH=${{ env.OUTPUT_PATH}}" >> $GITHUB_ENV - name: Check that new services have been added to the TeamCity configuration code run: | - # Create lists of service packages in providers - ls ${{env.GOOGLE_REPO_PATH}}/google/services > tools/teamcity-diff-check/services_ga.txt - ls ${{env.GOOGLE_BETA_REPO_PATH}}/google-beta/services > tools/teamcity-diff-check/services_beta.txt - + # Create lists of service packages in providers. Need to cd into repos where go.mod is to do this command. + cd ${{env.GOOGLE_REPO_PATH}} + go list -f '{{.Name}}' ${{env.GOOGLE_REPO_PATH}}/google/services/... > $GITHUB_WORKSPACE/provider_services_ga.txt + cd ${{env.GOOGLE_BETA_REPO_PATH}} + go list -f '{{.Name}}' ${{env.GOOGLE_BETA_REPO_PATH}}/google-beta/services/... > $GITHUB_WORKSPACE/provider_services_beta.txt + # Run tool to compare service packages in the providers vs those listed in TeamCity config files - cd tools/teamcity-diff-check - go run main.go -service_file=services_ga - go run main.go -service_file=services_beta + cd $GITHUB_WORKSPACE + go run ./tools/teamcity-diff-check/main.go -version=ga -provider_services=./provider_services_ga.txt -teamcity_services=./mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt + go run ./tools/teamcity-diff-check/main.go -version=beta -provider_services=./provider_services_beta.txt -teamcity_services=./mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt diff --git a/.github/workflows/teamcity-services-diff-check.yml b/.github/workflows/teamcity-services-diff-check.yml index a5ff3e1bc3a7..ea059c466c4a 100644 --- a/.github/workflows/teamcity-services-diff-check.yml +++ b/.github/workflows/teamcity-services-diff-check.yml @@ -52,11 +52,13 @@ jobs: - name: Check that new services have been added to the TeamCity configuration code if: steps.generate.outcome == 'success' run: | - # Create lists of service packages in providers - ls ${{env.GOOGLE_REPO_PATH}}/google/services > tools/teamcity-diff-check/services_ga.txt - ls ${{env.GOOGLE_BETA_REPO_PATH}}/google-beta/services > tools/teamcity-diff-check/services_beta.txt + # Create lists of service packages in providers. Need to cd into repos where go.mod is to do this command. + cd ${{env.GOOGLE_REPO_PATH}} + go list -f '{{.Name}}' ${{env.GOOGLE_REPO_PATH}}/google/services/... > $GITHUB_WORKSPACE/provider_services_ga.txt + cd ${{env.GOOGLE_BETA_REPO_PATH}} + go list -f '{{.Name}}' ${{env.GOOGLE_BETA_REPO_PATH}}/google-beta/services/... > $GITHUB_WORKSPACE/provider_services_beta.txt # Run tool to compare service packages in the providers vs those listed in TeamCity config files - cd tools/teamcity-diff-check - go run main.go -service_file=services_ga - go run main.go -service_file=services_beta + cd $GITHUB_WORKSPACE + go run ./tools/teamcity-diff-check/main.go -version=ga -provider_services=./provider_services_ga.txt -teamcity_services=./mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt + go run ./tools/teamcity-diff-check/main.go -version=beta -provider_services=./provider_services_beta.txt -teamcity_services=./mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index fd2a01863fdd..000000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.1.0 diff --git a/GNUmakefile b/GNUmakefile index bc83284d3c00..ff896acab357 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -85,11 +85,14 @@ clean-tgc: rm -rf ./tfplan2cai/converters/google/resources;\ rm -rf ./cai2hcl/*;\ find ./tfplan2cai/test/** -type f -exec git rm {} \; > /dev/null;\ + rm -rf ./v6/pkg/cai2hcl/*;\ + rm -rf ./v6/pkg/tfplan2cai/*;\ tgc: cd mmv1;\ - go run . --version beta --provider tgc --output $(OUTPUT_PATH)/tfplan2cai $(mmv1_compile);\ - go run . --version beta --provider tgc_cai2hcl --output $(OUTPUT_PATH)/cai2hcl $(mmv1_compile);\ + go run . --version beta --provider tgc --output $(OUTPUT_PATH)/tfplan2cai $(mmv1_compile)\ + && go run . --version beta --provider tgc_cai2hcl --output $(OUTPUT_PATH)/cai2hcl $(mmv1_compile)\ + && go run . --version beta --provider tgc_v6 --output $(OUTPUT_PATH)/v6/pkg $(mmv1_compile);\ tf-oics: cd mmv1;\ diff --git a/docs/content/best-practices/_index.md b/docs/content/best-practices/_index.md index 19c18f2d9d98..77afd2c383f2 100644 --- a/docs/content/best-practices/_index.md +++ b/docs/content/best-practices/_index.md @@ -1,4 +1,4 @@ --- title: "Best practices" -weight: 25 +weight: 60 --- diff --git a/docs/content/best-practices/common-resource-patterns.md b/docs/content/best-practices/common-resource-patterns.md new file mode 100644 index 000000000000..9cdc5e9f7f7d --- /dev/null +++ b/docs/content/best-practices/common-resource-patterns.md @@ -0,0 +1,17 @@ +--- +title: "Common resource patterns" +weight: 40 +--- + +# Common resource patterns + +## Singletons + +Singletons are resources – often config or settings objects – that can only exist once. In some cases, it may be possible to create and delete the resource (but only one can exist at a time); in other cases the resource _always_ exists and can only be read and updated. + +Implementing resources like this may require some or all of the following: + +1. If there _isn't_ a create endpoint, set the [create_url]({{< ref "/reference/resource-reference/#create_url" >}}) to point to the update endpoint. +1. If there _is_ a create endpoint, add [pre-create custom code]({{< ref "/develop/custom-code/#pre_post_injection" >}}) that implements "acquire-on-create" logic. The custom code should check whether the resource already exists with a read request, and if it does, run the update logic and return early. For example, see [mmv1/templates/terraform/pre_create/firebasehosting_site.go.tmpl](https://github.com/GoogleCloudPlatform/magic-modules/blob/dc4d9755cb9288177e0996c1c3b3fa9738ebdf89/mmv1/templates/terraform/pre_create/firebasehosting_site.go.tmpl). + * Note: The main disadvantage of "acquire-on-create" logic is that users will not be presented with a diff between the resource's old and new states – because from the terraform perspective, the resource is only being created. Please upvote https://github.com/hashicorp/terraform/issues/19017 to request better support for this workflow. +1. If there is no delete endpoint, set [`exclude_delete: true`]({{< ref "/reference/resource-reference/#create_url" >}}) at the top level of the resource. \ No newline at end of file diff --git a/docs/content/best-practices/deletion-behaviors.md b/docs/content/best-practices/deletion-behaviors.md index f88ae7da51bb..bb97ffdf64d8 100644 --- a/docs/content/best-practices/deletion-behaviors.md +++ b/docs/content/best-practices/deletion-behaviors.md @@ -11,10 +11,14 @@ weight: 20 ## Mitigating data loss risk via deletion_protection {#deletion_protection} -Some resources, such as databases, have a significant risk of unrecoverable data loss if the resource is accidentally deleted due to a change to a ForceNew field. For these resources, the best practice is to add a `deletion_protection` field that defaults to `true`, which prevents the resource from being deleted if enabled. Although it is a small breaking change, for users, the benefits of `deletion_protection` defaulting to `true` outweigh the cost. +Some resources, such as databases, have a significant risk of unrecoverable data loss if the resource is accidentally deleted due to a change to a ForceNew field. For these resources, the best practice is to add a `deletion_protection` field that prevents the resource from being deleted if enabled. -APIs also sometimes add `deletion_protection` fields, which will generally default to `false` for backwards-compatibility reasons. Any `deletion_protection` API field added to an existing Terraform resource must match the API default initially. The default may be set to `true` in the next major release. For new Terraform resources, any `deletion_protection` field should default to `true` in Terraform regardless of the API default. When creating the corresponding Terraform field, the name -should match the API field name (i.e. it need not literally be named `deletion_protection` if the API uses something different) and should be the same field type (example: if the API field is an enum, so should the Terraform field). +`deletion_protection` fields generally need to be added with a default of `false` that can be changed to `true` in the next major release, because adding deletion protection is a [major behavioral change]({{< ref "/breaking-changes/breaking-changes/#resource-level-breaking-changes" >}}). Exceptions to this are: + +- The API has a deletion protection field that defaults to enabled on the API side +- The `deletion_protection` field is being added at the same time as the resource + +If the API has a deletion protection field, the corresponding Terraform field name should match the API field's name and type. For example, if the API has an enum field called `what_to_do_on_delete` with values `DELETE` and `PROTECT`, the Terraform field should do the same. A resource can have up to two `deletion_protection` fields (with different names): one that represents a field in the API, and one that is only in Terraform. This could happen because the API added its field after `deletion_protection` already existed in Terraform; it could also happen because a separate field was added in Terraform to make sure that `deletion_protection` is enabled by default. In either case, they should be reconciled into a single field (that defaults to enabled and whose name matches the API field) in the next major release. @@ -33,3 +37,7 @@ Some resources need to let users control the actions taken add deletion time. Fo One common example is `ABANDON`, which is useful if the resource is safe to delete from Terraform but could cause problems if deleted from the API - for example, `google_bigtable_gc_policy` deletion can fail in replicated instances. `ABANDON` indicates that attempts to delete the resource should remove it from state without actually deleting it. See [Client-side fields]({{< ref "/develop/client-side-fields" >}}) for information about adding `deletion_policy` fields. + +## Exclude deletion {#exclude_delete} + +Some resources do not support deletion in the API and can only be removed from state. For these resources, the best practice is to set [`exclude_delete: true`]({{< ref "/reference/resource-reference#exclude_delete" >}}) on the resource. diff --git a/docs/content/breaking-changes/_index.md b/docs/content/breaking-changes/_index.md new file mode 100644 index 000000000000..b40ee5dc5a81 --- /dev/null +++ b/docs/content/breaking-changes/_index.md @@ -0,0 +1,4 @@ +--- +title: "Breaking changes" +weight: 46 +--- diff --git a/docs/content/develop/breaking-changes/breaking-changes.md b/docs/content/breaking-changes/breaking-changes.md similarity index 97% rename from docs/content/develop/breaking-changes/breaking-changes.md rename to docs/content/breaking-changes/breaking-changes.md index a84e644f72dc..807a146b2889 100644 --- a/docs/content/develop/breaking-changes/breaking-changes.md +++ b/docs/content/breaking-changes/breaking-changes.md @@ -5,6 +5,7 @@ aliases: - /docs/content/develop/breaking-changes - /reference/breaking-change-detector - /develop/breaking-changes +- /develop/breaking-changes/breaking-changes --- @@ -25,7 +26,7 @@ comprehensive. Some types of changes that would normally be "breaking" may have specific mitigating circumstances that make them non-breaking. For more information, see -[Make a breaking change]({{< ref "/develop/breaking-changes/make-a-breaking-change" >}}). +[Make a breaking change]({{< ref "/breaking-changes/make-a-breaking-change" >}}). ## Provider-level breaking changes diff --git a/docs/content/develop/breaking-changes/make-a-breaking-change.md b/docs/content/breaking-changes/make-a-breaking-change.md similarity index 96% rename from docs/content/develop/breaking-changes/make-a-breaking-change.md rename to docs/content/breaking-changes/make-a-breaking-change.md index bb4e62499955..d9d3a8c82e77 100644 --- a/docs/content/develop/breaking-changes/make-a-breaking-change.md +++ b/docs/content/breaking-changes/make-a-breaking-change.md @@ -6,13 +6,14 @@ summary: "Guidance on making a breaking changes" weight: 20 aliases: - /develop/make-a-breaking-change +- /develop/breaking-changes/make-a-breaking-change --- # Make a breaking change A "breaking change" is any change that requires an end user to modify any previously-valid configuration after a provider upgrade. For more information, -see [Types of breaking changes]({{< ref "/develop/breaking-changes" >}}). +see [Types of breaking changes]({{< ref "/breaking-changes/breaking-changes" >}}). The `google` and `google-beta` providers are both considered "stable surfaces" for the purpose of releases, which means that neither provider allows breaking @@ -115,7 +116,7 @@ The deprecation message will automatically show up in the resource documentation ``` Replace the second sentence with an appropriate short description of the replacement path and/or the reason for deprecation. -2. Update the [documentation for the field]({{< ref "/develop/resource#add-documentation" >}}) to include the deprecation notice. For example: +2. Update the [documentation for the field]({{< ref "/document/add-documentation" >}}) to include the deprecation notice. For example: ```markdown * `api_field_name` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Deprecated) FIELD_DESCRIPTION. `api_field_name` is deprecated and will be removed in a future major release. Use `other_field_name` instead. @@ -207,4 +208,4 @@ and other upgrade guides for examples. ## What's next? -- [Run tests]({{< ref "/develop/test/run-tests.md" >}}) +[Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/contribute/_index.md b/docs/content/contribute/_index.md index 1d84f70265de..0374d0fbe2cc 100644 --- a/docs/content/contribute/_index.md +++ b/docs/content/contribute/_index.md @@ -1,4 +1,4 @@ --- title: "Contribute" -weight: 30 +weight: 50 --- \ No newline at end of file diff --git a/docs/content/contribute/create-pr.md b/docs/content/contribute/create-pr.md index 4c8c24b95138..d360042870e6 100644 --- a/docs/content/contribute/create-pr.md +++ b/docs/content/contribute/create-pr.md @@ -17,14 +17,14 @@ weight: 10 ## Code review 1. A reviewer will automatically be assigned to your PR. -1. Creating a new pull request or pushing a new commit automatically triggers our CI pipelines and workflows. After CI starts, downstream diff generation takes about 10 minutes; [VCR tests]({{< ref "/develop/test/test.md" >}}) can take up to 2 hours. If you are a community contributor, some tests will only run after approval from a reviewer. - - While convenient, relying on CI to test iterative changes to PRs often adds extreme latency to reviews if there are errors in test configurations or at runtime. We **strongly** recommend you [test your changes locally before pushing]({{< ref "/develop/test/run-tests" >}}) even after the initial change. +1. Creating a new pull request or pushing a new commit automatically triggers our CI pipelines and workflows. After CI starts, downstream diff generation takes about 10 minutes; [VCR tests]({{< ref "/test/test" >}}) can take up to 2 hours. If you are a community contributor, some tests will only run after approval from a reviewer. + - While convenient, relying on CI to test iterative changes to PRs often adds extreme latency to reviews if there are errors in test configurations or at runtime. We **strongly** recommend you [test your changes locally before pushing]({{< ref "/test/run-tests" >}}) even after the initial change. - VCR tests will first attempt to play back recorded HTTP requests (REPLAYING mode). If any tests fail, they will run in RECORDING mode to generate a new cassette; then, the same tests will run again in REPLAYING mode to detect any nondeterministic behavior in the test (which can cause flaky tests.) 1. If your assigned reviewer does not respond to changes on a pull request within two US business days, ping them on the pull request. {{< hint info >}} **TIP:** Speeding up review: -1. [Test your changes locally before pushing]({{< ref "/develop/test/run-tests" >}}) to iterate faster. +1. [Test your changes locally before pushing]({{< ref "/test/run-tests" >}}) to iterate faster. - You can push them and test in parallel as well. New CI runs will preempt old ones where possible. 1. Resolve failed [status checks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks) quickly - Directly ask your reviewer for help if you don't know how to proceed. If there are failed checks they may only check in if there's no progress after a couple days. @@ -39,7 +39,7 @@ weight: 10 VCR test failures that do not immediately seem related to your PR are most likely safe to ignore unless your reviewer says otherwise. 1. Review the "diff generation" report to make sure the generated code looks as expected. -1. Check out the generated code for your PR to [run tests]({{< ref "/develop/test/run-tests" >}}) and iterate locally. For handwritten code or [custom code]({{< ref "/develop/custom-code" >}}), you can iterate directly in the provider and then copy the changes to your `magic-modules` branch once you have resolved the issue. +1. Check out the generated code for your PR to [run tests]({{< ref "/test/run-tests" >}}) and iterate locally. For handwritten code or [custom code]({{< ref "/develop/custom-code" >}}), you can iterate directly in the provider and then copy the changes to your `magic-modules` branch once you have resolved the issue. {{< tabs "checkout-auto-pr" >}} {{< tab "terraform-provider-google" >}} ```bash diff --git a/docs/content/contribute/review-pr.md b/docs/content/contribute/review-pr.md index b4508b814efe..e242b33e8a5f 100644 --- a/docs/content/contribute/review-pr.md +++ b/docs/content/contribute/review-pr.md @@ -17,7 +17,7 @@ This page provides guidelines for reviewing a Magic Modules pull request (PR). 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/make-a-breaking-change" >}}) are introduced without a valid justification. Add the `override-breaking-change` label if there is a valid justification. + 1. no [breaking changes]({{< ref "/breaking-changes/make-a-breaking-change" >}}) are introduced without a valid justification. Add the `override-breaking-change` label if there is a valid justification. * remember to check for changes in default behaviour like changing the flags on delete! 1. verify the change **fully** resolves the linked issues, if any. If it does not, change the "Fixes" message to "Part of". 1. Check the tests added/modified to ensure that: @@ -44,6 +44,6 @@ This page provides guidelines for reviewing a Magic Modules pull request (PR). {{< /hint >}} 1. a significant number of preexisting tests have not been modified. Changing old tests often indicates a change is backwards incompatible. 1. Check documentation to ensure - 1. resouce-level and field-level documentation are generated correctly for MMv1-based resource + 1. resource-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 merging the PR. diff --git a/docs/content/contribution-process.md b/docs/content/contribution-process.md index 5cff76fdbb2d..e7683ba25a43 100644 --- a/docs/content/contribution-process.md +++ b/docs/content/contribution-process.md @@ -1,6 +1,6 @@ --- title: "Contribution process" -weight: 11 +weight: 20 aliases: - /docs/getting-started/contributing - /getting-started/contributing @@ -16,7 +16,7 @@ This page explains how you can contribute code and documentation to the `magic-m 1. Familiarize yourself with [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) 1. [Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) the `Magic Modules` repository into your GitHub account -1. [Set up your development environment](https://googlecloudplatform.github.io/magic-modules/get-started/generate-providers/) +1. [Set up your development environment]({{< ref "/develop/set-up-dev-environment/" >}}) 1. Check whether the feature you want to work on has already been [requested in the issue tracker](https://github.com/hashicorp/terraform-provider-google/issues). - If there's an issue and it already has a dedicated assignee, this indicates that someone might have already started to work on a solution. Otherwise, you're welcome to work on the issue. @@ -25,13 +25,13 @@ This page explains how you can contribute code and documentation to the `magic-m 1. [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) 1. [Create a new branch for your change](https://docs.github.com/en/get-started/quickstart/github-flow#create-a-branch) 1. Make the code change. For example: - - [Add or modify a resource]({{< ref "/develop/resource" >}}) - - [Add resource tests]({{< ref "/develop/test/test" >}}) - - [Add a datasource]({{< ref "/develop/add-handwritten-datasource" >}}) - - [Promote to GA]({{< ref "/develop/promote-to-ga" >}}) - - [Make a breaking change]({{< ref "/develop/breaking-changes/make-a-breaking-change" >}}) + + [Add a resource]({{< ref "/develop/add-resource" >}}) + + [Add resource tests]({{< ref "/test/test" >}}) + + [Add a datasource]({{< ref "/develop/add-handwritten-datasource" >}}) + + [Promote to GA]({{< ref "/develop/promote-to-ga" >}}) + + [Make a breaking change]({{< ref "/breaking-changes/make-a-breaking-change" >}}) 1. [Generate the providers]({{< ref "/develop/generate-providers" >}}) that include your change. -1. [Run provider tests locally]({{< ref "/develop/test/run-tests" >}}) that are relevant to the change you made +1. [Run provider tests locally]({{< ref "/test/run-tests" >}}) that are relevant to the change you made 1. [Create a pull request (PR)]({{< ref "/contribute/create-pr" >}}) 1. Make changes in response to [code review]({{< ref "/contribute/create-pr#code-review" >}}) diff --git a/docs/content/develop/_index.md b/docs/content/develop/_index.md index c4e2bc1e09d0..cf547e9d098e 100644 --- a/docs/content/develop/_index.md +++ b/docs/content/develop/_index.md @@ -1,4 +1,4 @@ --- title: "Develop" -weight: 20 +weight: 30 --- diff --git a/docs/content/develop/add-fields.md b/docs/content/develop/add-fields.md new file mode 100644 index 000000000000..12d0642982fd --- /dev/null +++ b/docs/content/develop/add-fields.md @@ -0,0 +1,216 @@ +--- +title: "Add a field to an existing resource" +weight: 30 +--- + +# Add a field to an existing resource + +This page describes how to add a field to an existing resource in the `google` or `google-beta` Terraform +provider using MMv1 and/or handwritten code. In general, Terraform resources should implement all configurable +fields and all read-only fields. Even fields that seem like they would not be useful in Terraform +(like update time or etag) often end up being requested by users, so it's usually easier to just add them all at +once. However, optional or read-only fields can be omitted when adding a resource if they would require significant +additional work to implement. + +For more information about types of resources and the generation process overall, see [How Magic Modules works]({{< ref "/" >}}). + +## Before you begin + +1. Complete the steps in [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) to set up your environment and your Google Cloud project. +1. [Ensure the resource to which you want to add the fields exists in the provider]({{< ref "/develop/add-resource" >}}). +1. Ensure that your `magic-modules`, `terraform-provider-google`, and `terraform-provider-google-beta` repositories are up to date. + ``` + cd ~/magic-modules + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta + git checkout main && git clean -f . && git checkout -- . && git pull + ``` + +## Add fields + +{{< tabs "fields" >}} +{{< tab "MMv1" >}} +1. For each API field, copy the following template into the resource's `properties` attribute. Be sure to indent appropriately. + +{{< tabs "MMv1 types" >}} +{{< tab "Simple" >}} +```yaml +- name: 'API_FIELD_NAME' + type: String + description: | + MULTILINE_FIELD_DESCRIPTION + min_version: beta + immutable: true + required: true + output: true + conflicts: + - field_one + - nested_object.0.nested_field + exactly_one_of: + - field_one + - nested_object.0.nested_field + +``` + +Replace `String` in the field type with one of the following options: + +- `String` +- `Integer` +- `Boolean` +- `Double` +- `KeyValuePairs` (string -> string map) +- `KeyValueLabels` (for standard resource 'labels' field) +- `KeyValueAnnotations` (for standard resource 'annotations' field) +{{< /tab >}} +{{< tab "Enum" >}} +```yaml +- name: 'API_FIELD_NAME' + type: Enum + description: | + MULTILINE_FIELD_DESCRIPTION + min_version: beta + immutable: true + required: true + output: true + conflicts: + - field_one + - nested_object.0.nested_field + exactly_one_of: + - field_one + - nested_object.0.nested_field + enum_values: + - 'VALUE_ONE' + - 'VALUE_TWO' +``` +{{< /tab >}} +{{< tab "ResourceRef" >}} +```yaml +- name: 'API_FIELD_NAME' + type: ResourceRef + description: | + MULTILINE_FIELD_DESCRIPTION + min_version: beta + immutable: true + required: true + output: true + conflicts: + - field_one + - nested_object.0.nested_field + exactly_one_of: + - field_one + - nested_object.0.nested_field + resource: 'ResourceName' + imports: 'name' +``` +{{< /tab >}} +{{< tab "Array" >}} +```yaml +- name: 'API_FIELD_NAME' + type: Array + description: | + MULTILINE_FIELD_DESCRIPTION + min_version: beta + immutable: true + required: true + output: true + conflicts: + - field_one + - nested_object.0.nested_field + exactly_one_of: + - field_one + - nested_object.0.nested_field + # Array of primitives + item_type: + type: String + + # Array of nested objects + item_type: + type: NestedObject + properties: + - name: 'FIELD_NAME' + type: String + description: | + MULTI_LINE_FIELD_DESCRIPTION +``` +{{< /tab >}} +{{< tab "NestedObject" >}} +```yaml +- name: 'API_FIELD_NAME' + type: NestedObject + description: | + MULTILINE_FIELD_DESCRIPTION + min_version: beta + immutable: true + required: true + output: true + conflicts: + - field_one + - nested_object.0.nested_field + exactly_one_of: + - field_one + - nested_object.0.nested_field + properties: + - name: 'FIELD_NAME' + type: String + description: | + MULTI_LINE_FIELD_DESCRIPTION +``` +{{< /tab >}} +{{< tab "Map" >}} +```yaml + - name: 'API_FIELD_NAME' + type: Map + description: | + MULTILINE_FIELD_DESCRIPTION + key_name: 'KEY_NAME' + key_description: | + MULTILINE_KEY_FIELD_DESCRIPTION + value_type: + name: mapObjectName + type: NestedObject + properties: + - name: 'FIELD_NAME' + type: String + description: | + MULTI_LINE_FIELD_DESCRIPTION +``` + +This type is only used for string -> complex type mappings, use "KeyValuePairs" for simple mappings. Complex maps can't be represented natively in Terraform, and this type is transformed into an associative array (TypeSet) with the key merged into the object alongside other top-level fields. + +For `key_name` and `key_description`, provide a domain-appropriate name and description. For example, a map that references a specific type of resource would generally use the singular resource kind as the key name (such as "topic" for PubSub Topic) and a descriptor of the expected format depending on the context (such as resourceId vs full resource name). + +{{< /tab >}} +{{< /tabs >}} + +2. Modify the field configuration according to the API documentation and behavior. + +> **Note:** The templates in this section only include the most commonly-used fields. For a comprehensive reference, see [MMv1 field reference]({{}}). For information about modifying the values sent and received for a field, see [Modify the API request or response]({{}}). +{{< /tab >}} +{{< tab "Handwritten" >}} +1. Add the field to the handwritten resource's schema. + - The new field(s) should mirror the API's structure to ease predictability and maintenance. However, if there is an existing related / similar field in the resource that uses a different convention, follow that convention instead. + - Enum fields in the API should be represented as `TypeString` in Terraform for forwards-compatibility. Link to the API documentation of allowed values in the field description. + - Terraform field names should always use [snake case ↗](https://en.wikipedia.org/wiki/Snake_case). + - See [Schema Types ↗](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-types) and [Schema Behaviors ↗](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors) for more information about field schemas. +2. Add handling for the new field in the resource's Create method and Update methods. + - "Expanders" convert Terraform resource data to API request data. + - For top level fields, add an expander. If the field is set or has changed, call the expander and add the resulting value to the API request. + - For other fields, add logic to the parent field's expander to add the field to the API request. Use a nested expander for complex logic. +3. Add handling for the new field in the resource's Read method. + - "Flatteners" convert API response data to Terraform resource data. + - For top level fields, add a flattener. Call `d.Set()` on the flattened API response value to store it in Terraform state. + - For other fields, add logic to the parent field's flattener to convert the value from the API response to the Terraform state value. Use a nested flattener for complex logic. +4. If any of the added Go code (including any imports) is beta-only, change the file suffix to `.go.tmpl` and wrap the beta-only code in a version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}`. + - Add a new guard rather than adding the field to an existing guard; it is easier to read. +{{< /tab >}} +{{< /tabs >}} + +## What's next? + ++ [Add IAM support]({{< ref "/develop/add-iam-support" >}}) ++ [Add documentation]({{< ref "/document/add-documentation" >}}) ++ [Add custom resource code]({{< ref "/develop/custom-code" >}}) ++ [Add tests]({{< ref "/test/test" >}}) ++ [Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/add-handwritten-datasource.md b/docs/content/develop/add-handwritten-datasource.md index c25081f5ebf3..3b798ef862d2 100644 --- a/docs/content/develop/add-handwritten-datasource.md +++ b/docs/content/develop/add-handwritten-datasource.md @@ -1,7 +1,7 @@ --- title: "Add a datasource" summary: "Datasources are like terraform resources except they don't *create* anything." -weight: 14 +weight: 60 aliases: - /docs/how-to/add-handwritten-datasource - /how-to/add-handwritten-datasource @@ -51,6 +51,6 @@ library, or the raw HTTP client used in MMV1 through `SendRequest`. 1. Open the data source documentation in [`magic-modules/third_party/terraform/website/docs/d/`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/d) using an editor of your choice. - The name of the file is the name of the data source without a `google_` prefix. For example, for `google_compute_instance`, the file is called `compute_instance.html.markdown` -2. Modify the documentation as needed according to [Handwritten documentation style guide]({{< ref "/develop/handwritten-docs-style-guide" >}}). +2. Modify the documentation as needed according to [Handwritten documentation style guide]({{< ref "/document/handwritten-docs-style-guide" >}}). 4. [Generate the providers]({{< ref "/develop/generate-providers" >}}) 5. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. diff --git a/docs/content/develop/add-iam-support.md b/docs/content/develop/add-iam-support.md new file mode 100644 index 000000000000..b0d4339d4d12 --- /dev/null +++ b/docs/content/develop/add-iam-support.md @@ -0,0 +1,126 @@ +--- +title: "Add IAM support" +weight: 40 +--- + +# Add IAM support + +This page covers how to add IAM resources in Terraform if they are supported by a particular API resource (indicated by +`setIamPolicy` and `getIamPolicy` methods in the API documentation for the resource). + +For more information about types of resources and the generation process overall, see [How Magic Modules works]({{< ref "/" >}}). + +## Before you begin + +1. Complete the steps in [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) to set up your environment and your Google Cloud project. +1. Ensure that your `magic-modules`, `terraform-provider-google`, and `terraform-provider-google-beta` repositories are up to date. + ``` + cd ~/magic-modules + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta + git checkout main && git clean -f . && git checkout -- . && git pull + ``` + +## Add IAM support + +{{< tabs "IAM" >}} +{{< tab "MMv1" >}} +IAM support for MMv1-generated resources is configured within the `ResourceName.yaml` file, and will create the `google_product_resource_iam_policy`, `google_product_resource_iam_binding`, `google_product_resource_iam_member` resource, website, and test files for that resource target when an `iam_policy` block is present. + +1. Add the following top-level block to `ResourceName.yaml` directly above `parameters`. + +```yaml +iam_policy: + # Name of the field on the terraform IAM resources which references + # the parent resource. Update to match the parent resource's name. + parent_resource_attribute: 'resource_name' + # Character preceding setIamPolicy in the full URL for the API method. + # Usually `:` + method_name_separator: ':' + # HTTP method for getIamPolicy. Usually 'POST'. + fetch_iam_policy_verb: 'POST' + # Overrides the HTTP method for setIamPolicy. Default: 'POST' + # set_iam_policy_verb: 'POST' + + # 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}}' + + # If IAM conditions are supported, set this attribute to indicate how the + # conditions should be passed to the API. Allowed values: 'QUERY_PARAM', + # 'REQUEST_BODY', 'QUERY_PARAM_NESTED'. Note: 'QUERY_PARAM_NESTED' should + # only be used if the query param field contains a `.` + # iam_conditions_request_type: 'REQUEST_BODY' + + # Marks IAM support as beta-only + # min_version: beta +``` + +2. Modify the template as needed to match the API resource's documented behavior. These are the most commonly-used fields. For a comprehensive reference, see [MMv1 resource reference: `iam_policy` ↗]({{}}). +3. Delete all remaining comments in the IAM configuration (including attribute descriptions) that were copied from the above template. +{{< /tab >}} +{{< tab "Handwritten" >}} +> **Warning:** IAM support for handwritten resources should be implemented using MMv1. New handwritten IAM resources will only be accepted if they cannot be implemented using MMv1. + +### Add support in MMv1 + +1. Follow the MMv1 directions in [Add a 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) + - `exclude_resource` (set to `true`) + - `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. + +### Convert to handwritten (not usually necessary) + +1. [Generate the beta provider]({{< ref "/develop/generate-providers" >}}) +2. From the beta provider, copy the files generated for the IAM resources to the following locations: + - Resource: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) + - Documentation: [`magic-modules/mmv1/third_party/terraform/website/docs/r`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) + - Tests: In the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) +3. Modify the Go code as needed. + - Replace all occurrences of `github.com/hashicorp/terraform-provider-google-beta/google-beta` with `github.com/hashicorp/terraform-provider-google/google` + - Remove the comments at the top of the file. + - If any of the added Go code is beta-only: + - Change the file suffix to `.go.tmpl` + - Wrap each beta-only code block (including any imports) in a separate version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}` +4. Register the binding, member, and policy resources `handwrittenIAMResources` in [`magic-modules/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl`](https://github.com/GoogleCloudPlatform/magic-modules/blob/main/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl) + - Add a version guard for any beta-only resources. +{{< /tab >}} +{{< /tabs >}} + +## Add documentation + +{{< tabs "docs" >}} +{{< tab "MMv1" >}} +Documentation is autogenerated based on the resource and field configurations. To preview the documentation: + +1. [Generate the providers]({{< ref "/develop/generate-providers" >}}) +2. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. +{{< /tab >}} +{{< tab "Handwritten" >}} +### Add or modify documentation files + +1. Open the resource documentation in [`magic-modules/third_party/terraform/website/docs/r/`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) using an editor of your choice. + - The name of the file is the name of the resource without a `google_` prefix. For example, for `google_compute_instance`, the file is called `compute_instance.html.markdown` +2. Modify the documentation as needed according to [Handwritten documentation style guide]({{< ref "/document/handwritten-docs-style-guide" >}}). +3. [Generate the providers]({{< ref "/develop/generate-providers" >}}) +4. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. +{{< /tab >}} +{{< /tabs >}} + +## What's next? + ++ [Add documentation]({{< ref "/document/add-documentation" >}}) ++ [Add custom resource code]({{< ref "/develop/custom-code" >}}) ++ [Add tests]({{< ref "/test/test" >}}) ++ [Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/add-resource.md b/docs/content/develop/add-resource.md new file mode 100644 index 000000000000..4b7ce9702800 --- /dev/null +++ b/docs/content/develop/add-resource.md @@ -0,0 +1,184 @@ +--- +title: "Add a resource" +weight: 20 +aliases: + - /docs/how-to/add-mmv1-resource + - /how-to/add-mmv1-resource + - /develop/add-mmv1-resource + - /docs/how-to/mmv1-resource-documentation + - /how-to/mmv1-resource-documentation + - /develop/mmv1-resource-documentation + - /docs/how-to/add-mmv1-iam + - /how-to/add-mmv1-iam + - /develop/add-mmv1-iam + - /docs/how-to/update-handwritten-resource + - /how-to/update-handwritten-resource + - /develop/update-handwritten-resource + - /docs/how-to/update-handwritten-documentation + - /how-to/update-handwritten-documentation + - /develop/update-handwritten-documentation + - /docs/how-to + - /how-to + - /docs/getting-started/provider-documentation + - /getting-started/provider-documentation + - /develop/resource +--- + +# Add a resource + +This page describes how to add a new resource to the `google` or `google-beta` Terraform provider using MMv1 and/or handwritten code. + +For more information about types of resources and the generation process overall, see [How Magic Modules works]({{< ref "/" >}}). + +## Before you begin + +1. Complete the steps in [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) to set up your environment and your Google Cloud project. +1. Ensure that your `magic-modules`, `terraform-provider-google`, and `terraform-provider-google-beta` repositories are up to date. + ``` + cd ~/magic-modules + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta + git checkout main && git clean -f . && git checkout -- . && git pull + ``` + +## Add a resource + +{{< tabs "resource" >}} +{{< tab "MMv1" >}} +1. Using an editor of your choice, in the appropriate [product folder]({{}}), create a file called `RESOURCE_NAME.yaml`. Replace `RESOURCE_NAME` with the name of the API resource you are adding support for. For example, a configuration file for [NatAddress](https://cloud.google.com/apigee/docs/reference/apis/apigee/rest/v1/organizations.instances.natAddresses) would be called `NatAddress.yaml`. +2. Copy the following template into the new file: + ```yaml + # Copyright 2024 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. + + --- + # API resource name + name: 'ResourceName' + # Resource description for the provider documentation. + description: | + RESOURCE_DESCRIPTION + references: + guides: + # Link to quickstart in the API's Guides section. For example: + # 'Create and connect to a database': 'https://cloud.google.com/alloydb/docs/quickstart/create-and-connect' + 'QUICKSTART_TITLE': 'QUICKSTART_URL' + # Link to the REST API reference for the resource. For example, + # https://cloud.google.com/alloydb/docs/reference/rest/v1/projects.locations.backups + api: 'API_REFERENCE_URL' + # Marks the resource as beta-only. Ensure a beta version block is present in + # provider.yaml. + # min_version: beta + + # URL for the resource's standard List method. https://google.aip.dev/132 + # Terraform field names enclosed in double curly braces are replaced with + # the field values from the resource at runtime. + base_url: 'projects/{{project}}/locations/{{location}}/resourcenames' + # URL for the resource's standard Get method. https://google.aip.dev/131 + # Terraform field names enclosed in double curly braces are replaced with + # the field values from the resource at runtime. + self_link: 'projects/{{project}}/locations/{{location}}/resourcenames/{{name}}' + + # If true, the resource and all its fields are considered immutable - that is, + # only creatable, not updatable. Individual fields can override this if they + # have a custom update method in the API. + immutable: true + + # URL for the resource's standard Create method, including query parameters. + # https://google.aip.dev/133 + # Terraform field names enclosed in double curly braces are replaced with + # the field values from the resource at runtime. + create_url: 'projects/{{project}}/locations/{{location}}/resourcenames?resourceId={{name}}' + + # Overrides the URL for the resource's standard Update method. (If unset, the + # self_link URL is used by default.) https://google.aip.dev/134 + # Terraform field names enclosed in double curly braces are replaced with + # the field values from the resource at runtime. + # update_url: 'projects/{{project}}/locations/{{location}}/resourcenames/{{name}}' + # The HTTP verb used to update a resource. Allowed values: :POST, :PUT, :PATCH. Default: :PUT. + update_verb: 'PATCH' + # If true, the resource sets an `updateMask` query parameter listing modified + # fields when updating the resource. If false, it does not. + update_mask: true + + # If true, code for handling long-running operations is generated along with + # the resource. If false, that code is not generated. + autogen_async: true + # Sets parameters for handling operations returned by the API. + async: + # Overrides which API calls return operations. Default: ['create', + # 'update', 'delete'] + # actions: ['create', 'update', 'delete'] + operation: + base_url: '{{op_id}}' + + parameters: + - name: 'location' + type: String + required: true + immutable: true + url_param_only: true + description: | + LOCATION_DESCRIPTION + - name: 'name' + type: String + required: true + immutable: true + url_param_only: true + description: | + NAME_DESCRIPTION + + properties: + # Fields go here + ``` + +3. Modify the template as needed to match the API resource's documented behavior. +4. Delete all remaining comments in the resource configuration (including attribute descriptions) that were copied from the above template. + +> **Note:** The template includes the most commonly-used fields. For a comprehensive reference, see [MMv1 resource reference ↗]({{}}). +{{< /tab >}} +{{< tab "Handwritten" >}} +> **Warning:** Handwritten resources are more difficult to develop and maintain. New handwritten resources will only be accepted if implementing the resource in MMv1 would require entirely overriding two or more CRUD methods. + +1. Add the resource in MMv1. +2. [Generate the beta provider]({{< ref "/develop/generate-providers" >}}) +3. From the beta provider, copy the files generated for the resource to the following locations: + - Resource: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) + - Documentation: [`magic-modules/mmv1/third_party/terraform/website/docs/r`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) + - Tests: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services), and remove `_generated` from the filename + - Sweepers: Put to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services), and add `_sweeper` suffix to the filename +4. Modify the Go code as needed. + - Replace all occurrences of `github.com/hashicorp/terraform-provider-google-beta/google-beta` with `github.com/hashicorp/terraform-provider-google/google` + - Remove the `Example` suffix from all test function names. + - Remove the comments at the top of the file. + - If beta-only fields are being tested, do the following: + - Change the file suffix to `.go.tmpl` + - Wrap each beta-only test in a separate version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}` +5. Register the resource `handwrittenResources` in [`magic-modules/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl`](https://github.com/GoogleCloudPlatform/magic-modules/blob/main/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl) + - Add a version guard for any beta-only resources. +6. Optional: Complete other handwritten tasks that require the MMv1 configuration file. + - [Add resource tests]({{< ref "/test/test" >}}) + - [Add IAM support]({{}}) +7. Delete the MMv1 configuration file. +{{< /tab >}} +{{< /tabs >}} + +## What's next? + ++ [Add a field to an existing resource]({{< ref "/develop/add-fields" >}}) ++ [Add IAM support]({{< ref "/develop/add-iam-support" >}}) ++ [Add documentation]({{< ref "/document/add-documentation" >}}) ++ [Add custom resource code]({{< ref "/develop/custom-code" >}}) ++ [Add tests]({{< ref "/test/test" >}}) ++ [Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/breaking-changes/_index.md b/docs/content/develop/breaking-changes/_index.md deleted file mode 100644 index af7b2fb1558e..000000000000 --- a/docs/content/develop/breaking-changes/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Breaking changes" -weight: 100 -bookCollapseSection: true ---- diff --git a/docs/content/develop/client-side-fields.md b/docs/content/develop/client-side-fields.md index 8fb86446f220..ca3362900a04 100644 --- a/docs/content/develop/client-side-fields.md +++ b/docs/content/develop/client-side-fields.md @@ -1,6 +1,6 @@ --- title: "Client-side fields" -weight: 400 +weight: 150 --- # Client-side fields diff --git a/docs/content/develop/custom-code.md b/docs/content/develop/custom-code.md index 298e59b66cb2..52a62cae5acd 100644 --- a/docs/content/develop/custom-code.md +++ b/docs/content/develop/custom-code.md @@ -1,6 +1,6 @@ --- title: "Add custom resource code" -weight: 15 +weight: 70 --- # Add custom resource code @@ -32,12 +32,12 @@ Use `custom_code.constants` to inject top-level code in a resource file. This is - Constants - Regexes compiled at build time -- Functions, such as [diff suppress functions]({{}}), - [validation functions]({{}}), +- Functions, such as [diff suppress functions]({{}}), + [validation functions]({{}}), CustomizeDiff functions, and so on. - Methods -Any custom functions added should have thorough [unit tests]({{< ref "/develop/test/test#add-unit-tests" >}}). +Any custom functions added should have thorough [unit tests]({{< ref "/test/test#add-unit-tests" >}}). ## Modify the API request or response @@ -264,9 +264,9 @@ docs: * `FIELD_NAME` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) FIELD_DESCRIPTION ``` -See [Add documentation (Handwritten)]({{< ref "/develop/resource#add-documentation" >}}) for more information about what to include in the field documentation. +See [Add documentation (Handwritten)]({{< ref "/document/add-documentation" >}}) for more information about what to include in the field documentation. ## What's next? -- [Add tests]({{< ref "/develop/test/test.md" >}}) -- [Run tests]({{< ref "/develop/test/run-tests.md" >}}) ++ [Add tests]({{< ref "/test/test" >}}) ++ [Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/diffs.md b/docs/content/develop/diffs.md index a8785972636b..1248ab0baf64 100644 --- a/docs/content/develop/diffs.md +++ b/docs/content/develop/diffs.md @@ -1,6 +1,6 @@ --- title: "Fix diffs" -weight: 18 +weight: 100 aliases: - /develop/permadiff --- @@ -19,7 +19,7 @@ The sections below describe in more detail how to address a number of different ## API returns default value for unset field {#default} -For new fields, if possible, set a client-side default that matches the API default. This will prevent the diff and will allow users to accurately see what the end state will be if the field is not set in their configuration. A client-side default should only be used if the API sets the same default value in all cases and the default value will be stable over time. Changing a client-side default is a [breaking change]({{< ref "/develop/breaking-changes/breaking-changes" >}}). +For new fields, if possible, set a client-side default that matches the API default. This will prevent the diff and will allow users to accurately see what the end state will be if the field is not set in their configuration. A client-side default should only be used if the API sets the same default value in all cases and the default value will be stable over time. Changing a client-side default is a [breaking change]({{< ref "/breaking-changes/breaking-changes" >}}). {{< tabs "default_value" >}} {{< tab "MMv1" >}} @@ -130,7 +130,7 @@ diff_suppress_func: 'tpgresource.CaseDiffSuppress' diff_suppress_func: 'resourceNameFieldNameDiffSuppress' ``` -Define resource-specific functions in a [`custom_code.constants`](https://googlecloudplatform.github.io/magic-modules/develop/custom-code/#add-reusable-variables-and-functions) file. +Define resource-specific functions in a [`custom_code.constants`]({{< ref "/develop/custom-code/#add-reusable-variables-and-functions" >}}) file. ```go func resourceNameFieldNameDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { @@ -176,7 +176,7 @@ See [SDKv2 Schema Behaviors - DiffSuppressFunc ↗](https://developer.hashicorp. ## API field that is never included in the response {#ignore_read} -This is common for fields that store credentials or similar information. Such fields should also be marked as [`sensitive`]({{< ref "/develop/field-reference#sensitive" >}}). +This is common for fields that store credentials or similar information. Such fields should also be marked as [`sensitive`]({{< ref "/reference/field-reference#sensitive" >}}). In the flattener for the field, return the value of the field in the user's configuration. @@ -299,4 +299,4 @@ func flattenResourceNameFieldName(v interface{}, d *schema.ResourceData, config {{< /tab >}} {{< /tabs >}} -For other Array fields, convert the field to a Set – this is a [breaking change]({{< ref "/develop/breaking-changes/breaking-changes" >}}) and can only happen in a major release. +For other Array fields, convert the field to a Set – this is a [breaking change]({{< ref "/breaking-changes/breaking-changes" >}}) and can only happen in a major release. diff --git a/docs/content/develop/generate-providers.md b/docs/content/develop/generate-providers.md index c581b8099feb..129ce81d1361 100644 --- a/docs/content/develop/generate-providers.md +++ b/docs/content/develop/generate-providers.md @@ -1,6 +1,6 @@ --- title: "Generate the providers" -weight: 19 +weight: 110 aliases: - /docs/getting-started/setup - /getting-started/setup @@ -19,7 +19,7 @@ provider changes to the `google` and `google-beta` Terraform providers. 1. [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}). 1. Update `magic-modules` as needed. These updates could be any of the following changes: - + [Adding or modifying a resource]({{< ref "/develop/resource" >}}). + + [Adding a resource]({{< ref "/develop/add-resource" >}}). + [Adding a datasource]({{< ref "/develop/add-handwritten-datasource" >}}). + [Adding custom resource code]({{< ref "/develop/custom-code" >}}). + [Promoting a resource to GA]({{< ref "/develop/promote-to-ga" >}}). @@ -91,6 +91,6 @@ ulimit -n 8192 ## What's next -+ [Learn how to add resource tests]({{< ref "/develop/test/test" >}}) -+ [Learn how to run tests]({{< ref "/develop/test/run-tests" >}}) ++ [Learn how to add resource tests]({{< ref "/test/test" >}}) ++ [Learn how to run tests]({{< ref "/test/run-tests" >}}) + [Learn about `make` commands]({{< ref "/reference/make-commands" >}}) \ No newline at end of file diff --git a/docs/content/develop/promote-to-ga.md b/docs/content/develop/promote-to-ga.md index dbc9ac29b644..bd5f3fd1b2e0 100644 --- a/docs/content/develop/promote-to-ga.md +++ b/docs/content/develop/promote-to-ga.md @@ -1,6 +1,6 @@ --- title: "Promote to GA" -weight: 16 +weight: 80 --- # Promote from beta to GA @@ -72,4 +72,4 @@ For handwritten resources, modify the documentation as appropriate for your chan ## What's next? -- [Test your changes]({{< ref "/develop/test/run-tests.md" >}}) +- [Test your changes]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/resource.md b/docs/content/develop/resource.md deleted file mode 100644 index e66cd8b75f18..000000000000 --- a/docs/content/develop/resource.md +++ /dev/null @@ -1,463 +0,0 @@ ---- -title: "Add or modify a resource" -weight: 13 -aliases: - - /docs/how-to/add-mmv1-resource - - /how-to/add-mmv1-resource - - /develop/add-mmv1-resource - - /docs/how-to/mmv1-resource-documentation - - /how-to/mmv1-resource-documentation - - /develop/mmv1-resource-documentation - - /docs/how-to/add-mmv1-iam - - /how-to/add-mmv1-iam - - /develop/add-mmv1-iam - - /docs/how-to/update-handwritten-resource - - /how-to/update-handwritten-resource - - /develop/update-handwritten-resource - - /docs/how-to/update-handwritten-documentation - - /how-to/update-handwritten-documentation - - /develop/update-handwritten-documentation - - /docs/how-to - - /how-to - - /docs/getting-started/provider-documentation - - /getting-started/provider-documentation ---- - -# Add or modify a resource - -This page describes how to add a new resource to the `google` or `google-beta` Terraform provider using MMv1 and/or handwritten code. - -For more information about types of resources and the generation process overall, see [How Magic Modules works]({{< ref "/" >}}). - -## Before you begin - -1. Complete the steps in [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) to set up your environment and your Google Cloud project. -2. Ensure that your `magic-modules`, `terraform-provider-google`, and `terraform-provider-google-beta` repositories are up to date. - ``` - cd ~/magic-modules - git checkout main && git clean -f . && git checkout -- . && git pull - cd $GOPATH/src/github.com/hashicorp/terraform-provider-google - git checkout main && git clean -f . && git checkout -- . && git pull - cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta - git checkout main && git clean -f . && git checkout -- . && git pull - ``` - -## Add a resource - -{{< tabs "resource" >}} -{{< tab "MMv1" >}} -1. Using an editor of your choice, in the appropriate [product folder]({{}}), create a file called `RESOURCE_NAME.yaml`. Replace `RESOURCE_NAME` with the name of the API resource you are adding support for. For example, a configuration file for [NatAddress](https://cloud.google.com/apigee/docs/reference/apis/apigee/rest/v1/organizations.instances.natAddresses) would be called `NatAddress.yaml`. -2. Copy the following template into the new file: - ```yaml - # Copyright 2024 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. - - --- - # API resource name - name: 'ResourceName' - # Resource description for the provider documentation. - description: | - RESOURCE_DESCRIPTION - references: - guides: - # Link to quickstart in the API's Guides section. For example: - # 'Create and connect to a database': 'https://cloud.google.com/alloydb/docs/quickstart/create-and-connect' - 'QUICKSTART_TITLE': 'QUICKSTART_URL' - # Link to the REST API reference for the resource. For example, - # https://cloud.google.com/alloydb/docs/reference/rest/v1/projects.locations.backups - api: 'API_REFERENCE_URL' - # Marks the resource as beta-only. Ensure a beta version block is present in - # provider.yaml. - # min_version: beta - - # URL for the resource's standard List method. https://google.aip.dev/132 - # Terraform field names enclosed in double curly braces are replaced with - # the field values from the resource at runtime. - base_url: 'projects/{{project}}/locations/{{location}}/resourcenames' - # URL for the resource's standard Get method. https://google.aip.dev/131 - # Terraform field names enclosed in double curly braces are replaced with - # the field values from the resource at runtime. - self_link: 'projects/{{project}}/locations/{{location}}/resourcenames/{{name}}' - - # If true, the resource and all its fields are considered immutable - that is, - # only creatable, not updatable. Individual fields can override this if they - # have a custom update method in the API. - immutable: true - - # URL for the resource's standard Create method, including query parameters. - # https://google.aip.dev/133 - # Terraform field names enclosed in double curly braces are replaced with - # the field values from the resource at runtime. - create_url: 'projects/{{project}}/locations/{{location}}/resourcenames?resourceId={{name}}' - - # Overrides the URL for the resource's standard Update method. (If unset, the - # self_link URL is used by default.) https://google.aip.dev/134 - # Terraform field names enclosed in double curly braces are replaced with - # the field values from the resource at runtime. - # update_url: 'projects/{{project}}/locations/{{location}}/resourcenames/{{name}}' - # The HTTP verb used to update a resource. Allowed values: :POST, :PUT, :PATCH. Default: :PUT. - update_verb: 'PATCH' - # If true, the resource sets an `updateMask` query parameter listing modified - # fields when updating the resource. If false, it does not. - update_mask: true - - # If true, code for handling long-running operations is generated along with - # the resource. If false, that code is not generated. - autogen_async: true - # Sets parameters for handling operations returned by the API. - async: - # Overrides which API calls return operations. Default: ['create', - # 'update', 'delete'] - # actions: ['create', 'update', 'delete'] - operation: - base_url: '{{op_id}}' - - parameters: - - name: 'location' - type: String - required: true - immutable: true - url_param_only: true - description: | - LOCATION_DESCRIPTION - - name: 'name' - type: String - required: true - immutable: true - url_param_only: true - description: | - NAME_DESCRIPTION - - properties: - # Fields go here - ``` - -3. Modify the template as needed to match the API resource's documented behavior. -4. Delete all remaining comments in the resource configuration (including attribute descriptions) that were copied from the above template. - -> **Note:** The template includes the most commonly-used fields. For a comprehensive reference, see [MMv1 resource reference ↗]({{}}). -{{< /tab >}} -{{< tab "Handwritten" >}} -> **Warning:** Handwritten resources are more difficult to develop and maintain. New handwritten resources will only be accepted if implementing the resource in MMv1 would require entirely overriding two or more CRUD methods. - -1. Add the resource in MMv1. -2. [Generate the beta provider]({{< ref "/develop/generate-providers.md" >}}) -3. From the beta provider, copy the files generated for the resource to the following locations: - - Resource: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) - - Documentation: [`magic-modules/mmv1/third_party/terraform/website/docs/r`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) - - Tests: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services), and remove `_generated` from the filename - - Sweepers: Put to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services), and add `_sweeper` suffix to the filename -4. Modify the Go code as needed. - - Replace all occurrences of `github.com/hashicorp/terraform-provider-google-beta/google-beta` with `github.com/hashicorp/terraform-provider-google/google` - - Remove the `Example` suffix from all test function names. - - Remove the comments at the top of the file. - - If beta-only fields are being tested, do the following: - - Change the file suffix to `.go.tmpl` - - Wrap each beta-only test in a separate version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}` -5. Register the resource `handwrittenResources` in [`magic-modules/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl`](https://github.com/GoogleCloudPlatform/magic-modules/blob/main/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl) - - Add a version guard for any beta-only resources. -6. Optional: Complete other handwritten tasks that require the MMv1 configuration file. - - [Add resource tests]({{< ref "/develop/test/test.md" >}}) - - [Add IAM support]({{}}) -7. Delete the MMv1 configuration file. -{{< /tab >}} -{{< /tabs >}} - -## Add fields - -In general, Terraform resources should implement all configurable fields and all read-only fields. -Even fields that seem like they would not be useful in Terraform (like update time or etag) often -end up being requested by users, so it's usually easier to just add them all at once. However, -optional or read-only fields can be omitted when adding a resource if they would require significant -additional work to implement. - -{{< tabs "fields" >}} -{{< tab "MMv1" >}} -1. For each API field, copy the following template into the resource's `properties` attribute. Be sure to indent appropriately. - -{{< tabs "MMv1 types" >}} -{{< tab "Simple" >}} -```yaml -- name: 'API_FIELD_NAME' - type: String - description: | - MULTILINE_FIELD_DESCRIPTION - min_version: beta - immutable: true - required: true - output: true - conflicts: - - field_one - - nested_object.0.nested_field - exactly_one_of: - - field_one - - nested_object.0.nested_field - -``` - -Replace `String` in the field type with one of the following options: - -- `String` -- `Integer` -- `Boolean` -- `Double` -- `KeyValuePairs` (string -> string map) -- `KeyValueLabels` (for standard resource 'labels' field) -- `KeyValueAnnotations` (for standard resource 'annotations' field) -{{< /tab >}} -{{< tab "Enum" >}} -```yaml -- name: 'API_FIELD_NAME' - type: Enum - description: | - MULTILINE_FIELD_DESCRIPTION - min_version: beta - immutable: true - required: true - output: true - conflicts: - - field_one - - nested_object.0.nested_field - exactly_one_of: - - field_one - - nested_object.0.nested_field - enum_values: - - 'VALUE_ONE' - - 'VALUE_TWO' -``` -{{< /tab >}} -{{< tab "ResourceRef" >}} -```yaml -- name: 'API_FIELD_NAME' - type: ResourceRef - description: | - MULTILINE_FIELD_DESCRIPTION - min_version: beta - immutable: true - required: true - output: true - conflicts: - - field_one - - nested_object.0.nested_field - exactly_one_of: - - field_one - - nested_object.0.nested_field - resource: 'ResourceName' - imports: 'name' -``` -{{< /tab >}} -{{< tab "Array" >}} -```yaml -- name: 'API_FIELD_NAME' - type: Array - description: | - MULTILINE_FIELD_DESCRIPTION - min_version: beta - immutable: true - required: true - output: true - conflicts: - - field_one - - nested_object.0.nested_field - exactly_one_of: - - field_one - - nested_object.0.nested_field - # Array of primitives - item_type: - type: String - - # Array of nested objects - item_type: - type: NestedObject - properties: - - name: 'FIELD_NAME' - type: String - description: | - MULTI_LINE_FIELD_DESCRIPTION -``` -{{< /tab >}} -{{< tab "NestedObject" >}} -```yaml -- name: 'API_FIELD_NAME' - type: NestedObject - description: | - MULTILINE_FIELD_DESCRIPTION - min_version: beta - immutable: true - required: true - output: true - conflicts: - - field_one - - nested_object.0.nested_field - exactly_one_of: - - field_one - - nested_object.0.nested_field - properties: - - name: 'FIELD_NAME' - type: String - description: | - MULTI_LINE_FIELD_DESCRIPTION -``` -{{< /tab >}} -{{< tab "Map" >}} -```yaml - - name: 'API_FIELD_NAME' - type: Map - description: | - MULTILINE_FIELD_DESCRIPTION - key_name: 'KEY_NAME' - key_description: | - MULTILINE_KEY_FIELD_DESCRIPTION - value_type: - name: mapObjectName - type: NestedObject - properties: - - name: 'FIELD_NAME' - type: String - description: | - MULTI_LINE_FIELD_DESCRIPTION -``` - -This type is only used for string -> complex type mappings, use "KeyValuePairs" for simple mappings. Complex maps can't be represented natively in Terraform, and this type is transformed into an associative array (TypeSet) with the key merged into the object alongside other top-level fields. - -For `key_name` and `key_description`, provide a domain-appropriate name and description. For example, a map that references a specific type of resource would generally use the singular resource kind as the key name (such as "topic" for PubSub Topic) and a descriptor of the expected format depending on the context (such as resourceId vs full resource name). - -{{< /tab >}} -{{< /tabs >}} - -2. Modify the field configuration according to the API documentation and behavior. - -> **Note:** The templates in this section only include the most commonly-used fields. For a comprehensive reference, see [MMv1 field reference]({{}}). For information about modifying the values sent and received for a field, see [Modify the API request or response]({{}}). -{{< /tab >}} -{{< tab "Handwritten" >}} -1. Add the field to the handwritten resource's schema. - - The new field(s) should mirror the API's structure to ease predictability and maintenance. However, if there is an existing related / similar field in the resource that uses a different convention, follow that convention instead. - - Enum fields in the API should be represented as `TypeString` in Terraform for forwards-compatibility. Link to the API documentation of allowed values in the field description. - - Terraform field names should always use [snake case ↗](https://en.wikipedia.org/wiki/Snake_case). - - See [Schema Types ↗](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-types) and [Schema Behaviors ↗](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors) for more information about field schemas. -2. Add handling for the new field in the resource's Create method and Update methods. - - "Expanders" convert Terraform resource data to API request data. - - For top level fields, add an expander. If the field is set or has changed, call the expander and add the resulting value to the API request. - - For other fields, add logic to the parent field's expander to add the field to the API request. Use a nested expander for complex logic. -3. Add handling for the new field in the resource's Read method. - - "Flatteners" convert API response data to Terraform resource data. - - For top level fields, add a flattener. Call `d.Set()` on the flattened API response value to store it in Terraform state. - - For other fields, add logic to the parent field's flattener to convert the value from the API response to the Terraform state value. Use a nested flattener for complex logic. -4. If any of the added Go code (including any imports) is beta-only, change the file suffix to `.go.tmpl` and wrap the beta-only code in a version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}`. - - Add a new guard rather than adding the field to an existing guard; it is easier to read. -{{< /tab >}} -{{< /tabs >}} - - -## Add IAM support - -This section covers how to add IAM resources in Terraform if they are supported by a particular API resource (indicated by `setIamPolicy` and `getIamPolicy` methods in the API documentation for the resource). - -{{< tabs "IAM" >}} -{{< tab "MMv1" >}} -IAM support for MMv1-generated resources is configured within the `ResourceName.yaml` file, and will create the `google_product_resource_iam_policy`, `google_product_resource_iam_binding`, `google_product_resource_iam_member` resource, website, and test files for that resource target when an `iam_policy` block is present. - -1. Add the following top-level block to `ResourceName.yaml` directly above `parameters`. - -```yaml -iam_policy: - # Name of the field on the terraform IAM resources which references - # the parent resource. Update to match the parent resource's name. - parent_resource_attribute: 'resource_name' - # Character preceding setIamPolicy in the full URL for the API method. - # Usually `:` - method_name_separator: ':' - # HTTP method for getIamPolicy. Usually 'POST'. - fetch_iam_policy_verb: 'POST' - # Overrides the HTTP method for setIamPolicy. Default: 'POST' - # set_iam_policy_verb: 'POST' - - # 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}}' - - # If IAM conditions are supported, set this attribute to indicate how the - # conditions should be passed to the API. Allowed values: 'QUERY_PARAM', - # 'REQUEST_BODY', 'QUERY_PARAM_NESTED'. Note: 'QUERY_PARAM_NESTED' should - # only be used if the query param field contains a `.` - # iam_conditions_request_type: 'REQUEST_BODY' - - # Marks IAM support as beta-only - # min_version: beta -``` - -2. Modify the template as needed to match the API resource's documented behavior. These are the most commonly-used fields. For a comprehensive reference, see [MMv1 resource reference: `iam_policy` ↗]({{}}). -3. Delete all remaining comments in the IAM configuration (including attribute descriptions) that were copied from the above template. -{{< /tab >}} -{{< tab "Handwritten" >}} -> **Warning:** IAM support for handwritten resources should be implemented using MMv1. New handwritten IAM resources will only be accepted if they cannot be implemented using MMv1. - -### Add support in MMv1 - -1. Follow the MMv1 directions in [Add a 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) - - `exclude_resource` (set to `true`) - - `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. - -### Convert to handwritten (not usually necessary) - -1. [Generate the beta provider]({{< ref "/develop/generate-providers.md" >}}) -2. From the beta provider, copy the files generated for the IAM resources to the following locations: - - Resource: Copy to the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) - - Documentation: [`magic-modules/mmv1/third_party/terraform/website/docs/r`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) - - Tests: In the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) -3. Modify the Go code as needed. - - Replace all occurrences of `github.com/hashicorp/terraform-provider-google-beta/google-beta` with `github.com/hashicorp/terraform-provider-google/google` - - Remove the comments at the top of the file. - - If any of the added Go code is beta-only: - - Change the file suffix to `.go.tmpl` - - Wrap each beta-only code block (including any imports) in a separate version guard: `{{- if ne $.TargetVersionName "ga" -}}...{{- else }}...{{- end }}` -4. Register the binding, member, and policy resources `handwrittenIAMResources` in [`magic-modules/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl`](https://github.com/GoogleCloudPlatform/magic-modules/blob/main/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl) - - Add a version guard for any beta-only resources. -{{< /tab >}} -{{< /tabs >}} - -## Add documentation - -{{< tabs "docs" >}} -{{< tab "MMv1" >}} -Documentation is autogenerated based on the resource and field configurations. To preview the documentation: - -1. [Generate the providers]({{< ref "/develop/generate-providers.md" >}}) -2. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. -{{< /tab >}} -{{< tab "Handwritten" >}} -### Add or modify documentation files - -1. Open the resource documentation in [`magic-modules/third_party/terraform/website/docs/r/`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) using an editor of your choice. - - The name of the file is the name of the resource without a `google_` prefix. For example, for `google_compute_instance`, the file is called `compute_instance.html.markdown` -2. Modify the documentation as needed according to [Handwritten documentation style guide]({{< ref "/develop/handwritten-docs-style-guide" >}}). -3. [Generate the providers]({{< ref "/develop/generate-providers.md" >}}) -4. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. -{{< /tab >}} -{{< /tabs >}} - -## What's next? - -- [Add custom resource code]({{< ref "/develop/custom-code.md" >}}) -- [Add tests]({{< ref "/develop/test/test.md" >}}) -- [Run tests]({{< ref "/develop/test/run-tests.md" >}}) diff --git a/docs/content/develop/set-up-dev-environment.md b/docs/content/develop/set-up-dev-environment.md index f325c1865b50..574f30d3f0ee 100644 --- a/docs/content/develop/set-up-dev-environment.md +++ b/docs/content/develop/set-up-dev-environment.md @@ -1,6 +1,6 @@ --- title: "Set up your development environment" -weight: 12 +weight: 10 --- # Set up your development environment @@ -70,7 +70,7 @@ development environment. ## What's next -+ [Learn how to add or modify a resource]({{< ref "/develop/resource" >}}) ++ [Learn how to add a resource]({{< ref "/develop/add-resource" >}}) + [Learn how to add custom resource code]({{< ref "/develop/custom-code" >}}) + [Learn how to add a datasource]({{< ref "/develop/add-handwritten-datasource" >}}) + [Learn how to promote a resource to GA]({{< ref "/develop/promote-to-ga" >}}) diff --git a/docs/content/develop/test/_index.md b/docs/content/develop/test/_index.md deleted file mode 100644 index a632456e02f6..000000000000 --- a/docs/content/develop/test/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Test" -weight: 60 -bookCollapseSection: true ---- diff --git a/docs/content/develop/update-dependencies.md b/docs/content/develop/update-dependencies.md index b50d31b5afe2..5932b51aa789 100644 --- a/docs/content/develop/update-dependencies.md +++ b/docs/content/develop/update-dependencies.md @@ -1,6 +1,6 @@ --- title: "Update dependencies" -weight: 17 +weight: 90 aliases: - /docs/update-dependencies --- diff --git a/docs/content/document/_index.md b/docs/content/document/_index.md new file mode 100644 index 000000000000..b8be1d6b2f1b --- /dev/null +++ b/docs/content/document/_index.md @@ -0,0 +1,4 @@ +--- +title: "Document" +weight: 45 +--- \ No newline at end of file diff --git a/docs/content/document/add-documentation.md b/docs/content/document/add-documentation.md new file mode 100644 index 000000000000..3bc4c529b536 --- /dev/null +++ b/docs/content/document/add-documentation.md @@ -0,0 +1,52 @@ +--- +title: "Add documentation" +weight: 10 +aliases: + - /develop/add-documentation +--- + +# Add documentation + +Documentation is autogenerated based on the resource and field configurations. This page describes how to add documentation to resources and fields. + +For more information about types of resources and the generation process overall, see [How Magic Modules works]({{< ref "/" >}}). + +## Before you begin + +1. Complete the steps in [Set up your development environment]({{< ref "/develop/set-up-dev-environment" >}}) to set up your environment and your Google Cloud project. +1. Ensure that your `magic-modules`, `terraform-provider-google`, and `terraform-provider-google-beta` repositories are up to date. + ``` + cd ~/magic-modules + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google + git checkout main && git clean -f . && git checkout -- . && git pull + cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta + git checkout main && git clean -f . && git checkout -- . && git pull + ``` + +## Add documentation + +{{< tabs "docs" >}} +{{< tab "MMv1" >}} +To preview the documentation: + +1. [Generate the providers]({{< ref "/develop/generate-providers" >}}) +2. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. +{{< /tab >}} +{{< tab "Handwritten" >}} + +### Add or modify documentation files + +1. Open the resource documentation in [`magic-modules/third_party/terraform/website/docs/r/`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/website/docs/r) using an editor of your choice. + - The name of the file is the name of the resource without a `google_` prefix. For example, for `google_compute_instance`, the file is called `compute_instance.html.markdown` +2. Modify the documentation as needed according to [Handwritten documentation style guide]({{< ref "/document/handwritten-docs-style-guide" >}}). +3. [Generate the providers]({{< ref "/develop/generate-providers" >}}) +4. Copy and paste the generated documentation into the Hashicorp Registry's [Doc Preview Tool](https://registry.terraform.io/tools/doc-preview) to see how it is rendered. +{{< /tab >}} +{{< /tabs >}} + +## What's next? + ++ [Add custom resource code]({{< ref "/develop/custom-code" >}}) ++ [Add tests]({{< ref "/test/test" >}}) ++ [Run tests]({{< ref "/test/run-tests" >}}) diff --git a/docs/content/develop/handwritten-docs-style-guide.md b/docs/content/document/handwritten-docs-style-guide.md similarity index 98% rename from docs/content/develop/handwritten-docs-style-guide.md rename to docs/content/document/handwritten-docs-style-guide.md index c60dd1558ee0..d3f093594fd0 100644 --- a/docs/content/develop/handwritten-docs-style-guide.md +++ b/docs/content/document/handwritten-docs-style-guide.md @@ -1,6 +1,8 @@ --- title: Handwritten docs style guide -weight: 200 +weight: 20 +aliases: + - /develop/handwritten-docs-style-guide --- # Handwritten documentation style guide diff --git a/docs/content/reference/_index.md b/docs/content/reference/_index.md index 988fb960dd5a..f24812db55e3 100644 --- a/docs/content/reference/_index.md +++ b/docs/content/reference/_index.md @@ -1,4 +1,4 @@ --- title: "Reference" -weight: 40 +weight: 70 --- \ No newline at end of file diff --git a/docs/content/develop/field-reference.md b/docs/content/reference/field-reference.md similarity index 94% rename from docs/content/develop/field-reference.md rename to docs/content/reference/field-reference.md index 6946af19495f..36e61f3e243f 100644 --- a/docs/content/develop/field-reference.md +++ b/docs/content/reference/field-reference.md @@ -1,8 +1,9 @@ --- title: "MMv1 field reference" -weight: 31 +weight: 20 aliases: - /reference/field-reference + - /develop/field-reference --- # MMv1 field reference @@ -12,6 +13,14 @@ available properties, see [type.go ↗](https://github.com/GoogleCloudPlatform/m ## Shared properties +### `name` +Specifies the name of the field within Terraform. By default this will also +be the key for the field in the API request message, if a separate `api_name` +is not declared using the corresponding property. + +### `type` +Sets the expected data type of the field. All valid types are declared [here](https://github.com/GoogleCloudPlatform/magic-modules/blob/d7777055cb7618648725abd16d3b05e5c138fc56/mmv1/api/type.go#L673). + ### `min_version: beta` Marks the field (and any subfields) as beta-only. Ensure a beta version block is present in provider.yaml. Do not use if an ancestor field (or the overall @@ -232,7 +241,7 @@ Example: ### `diff_suppress_func` Specifies the name of a [diff suppress function](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#diffsuppressfunc) -to use for this field. In many cases, a [custom flattener](https://googlecloudplatform.github.io/magic-modules/develop/custom-code/#custom_flatten) +to use for this field. In many cases, a [custom flattener]({{< ref "/develop/custom-code/#custom_flatten" >}}) is preferred because it will allow the user to see a clearer diff when the field actually is being changed. See [Fix diffs]({{< ref "/develop/diffs" >}}) for more information and best practices. @@ -272,7 +281,7 @@ This property has two mutually exclusive child properties: [`function: verify.ValidateRegexp(REGEX_STRING)`](https://github.com/hashicorp/terraform-provider-google-beta/blob/0ef51142a4dd1c1a4fc308c1eb09dce307ebe5f5/google-beta/verify/validation.go#L425). `validation` is not supported for Array fields (including sets); however, individual -elements in the array can be validated using [`item_validation`]({{}}). +elements in the array can be validated using [`item_validation`]({{}}). Example: Provider-specific function @@ -323,7 +332,7 @@ stating the current allowed values in the String field's description. Do not include UNSPECIFIED values in this list. Enums will validate that the provided field is in the allowed list unless a -custom [`validation`]({{}}) is provided. +custom [`validation`]({{}}) is provided. Example: @@ -372,7 +381,7 @@ item_type: ### `item_validation` Array only. Controls the [`ValidateFunc`](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#validatefunc) -used to validate individual items in the array. Behaves like [`validation`]({{}}). +used to validate individual items in the array. Behaves like [`validation`]({{}}). For arrays of enums, this will override the default validation (that the provided value is one of the enum [`values`](#values)). If you need additional validation on top of an enum, ensure that the supplied validation func also verifies the enum diff --git a/docs/content/reference/make-commands.md b/docs/content/reference/make-commands.md index 4da3c758ac31..6742b44173a8 100644 --- a/docs/content/reference/make-commands.md +++ b/docs/content/reference/make-commands.md @@ -1,6 +1,6 @@ --- title: "make commands" -weight: 10 +weight: 30 --- # `make` commands reference @@ -34,7 +34,7 @@ make provider VERSION=ga OUTPUT_PATH="$GOPATH/src/github.com/hashicorp/terraform - `OUTPUT_PATH`: Required. The location you are generating provider code into. - `VERSION`: Required. The version of the provider you are building into. Valid values are `ga` and `beta`. -- `PRODUCT`: Limits generations to the specified folder within `mmv1/products` or `tpgtools/api`. Handwritten files from `mmv1/third_party/terraform` are always generated into the downstream regardless of this setting, so you can provide a non-existant product name to generate only handwritten code. Required if `RESOURCE` is specified. +- `PRODUCT`: Limits generations to the specified folder within `mmv1/products` or `tpgtools/api`. Handwritten files from `mmv1/third_party/terraform` are always generated into the downstream regardless of this setting, so you can provide a non-existent product name to generate only handwritten code. Required if `RESOURCE` is specified. - `RESOURCE`: Limits generation to the specified resource within a particular product. For `mmv1` resources, matches the resource's `name` field (set in its configuration file).For `tpgtools` resources, matches the terraform resource name. - `ENGINE`: Modifies `make provider` to only generate code using the specified engine. Valid values are `mmv1` or `tpgtools`. (Providing `tpgtools` will still generate any prerequisite mmv1 files required for tpgtools.) diff --git a/docs/content/develop/resource-reference.md b/docs/content/reference/resource-reference.md similarity index 91% rename from docs/content/develop/resource-reference.md rename to docs/content/reference/resource-reference.md index a00786d1ffd4..73aec50bd3d8 100644 --- a/docs/content/develop/resource-reference.md +++ b/docs/content/reference/resource-reference.md @@ -1,9 +1,10 @@ --- title: "MMv1 resource reference" -weight: 32 +weight: 10 aliases: - /reference/resource-reference - /reference/iam-policy-reference + - /develop/resource-reference --- # MMv1 resource reference @@ -99,7 +100,7 @@ If true, the resource and all its fields are considered immutable - that is, only creatable, not updatable. Individual fields can override this if they have a custom update method in the API. -See [Best practices: ForceNew](https://googlecloudplatform.github.io/magic-modules/best-practices/#forcenew) for more information. +See [Best practices: Immutable fields]({{< ref "/best-practices/immutable-fields/" >}}) for more information. Default: `false` @@ -205,6 +206,14 @@ Example: delete_verb: 'POST' ``` +### `exclude_delete` +If true, deleting the resource will only remove it from the Terraform state and will not call an API. If false, deleting the resource will run the standard deletion behavior and/or any [custom code]({{< ref "/develop/custom-code" >}}) related to deletion. +This should be used if the resource can never be deleted in the API, and there is no other reasonable action to take on deletion. See [Deletion behaviors]({{< ref "/best-practices/deletion-behaviors" >}}) for more information. + +```yaml +exclude_delete: true +``` + ### `autogen_async` If true, code for handling long-running operations is generated along with @@ -326,12 +335,12 @@ the behavior of a Terraform resource such as `deletion_protection`. ### `parameters` -Contains a list of [fields]({{< ref "/develop/field-reference" >}}). By convention, +Contains a list of [fields]({{< ref "/reference/field-reference" >}}). By convention, these should be the fields that are part URL parameters such as `location` and `name`. ### `properties` -Contains a list of [fields]({{< ref "/develop/field-reference" >}}). By convention, +Contains a list of [fields]({{< ref "/reference/field-reference" >}}). By convention, these should be fields that aren't part of the URL parameters. Example: diff --git a/docs/content/reference/ruby-go-changes.md b/docs/content/reference/ruby-go-changes.md index 41cec6dd2745..eac38ea6c090 100644 --- a/docs/content/reference/ruby-go-changes.md +++ b/docs/content/reference/ruby-go-changes.md @@ -1,6 +1,6 @@ --- title: "Ruby to Go Migration" -weight: 10 +weight: 40 --- # What has changed in the MMv1 Go migration @@ -83,7 +83,7 @@ resource "google_pubsub_topic" "{{$.PrimaryResourceId}}" { ## Advanced: MMv1-specific generator command -Most contributors should use the make commands referenced in [make-commands](https://googlecloudplatform.github.io/magic-modules/reference/make-commands/) reference page to generate the downstream `google` and `google-beta` providers. The input for these commands have not changed, and have already been correctly switched over to use the new Go engine. +Most contributors should use the make commands referenced in [make-commands]({{< ref "reference/make-commands/" >}}) reference page to generate the downstream `google` and `google-beta` providers. The input for these commands have not changed, and have already been correctly switched over to use the new Go engine. Some advanced contributors may be used to running the MMv1 generator commands. These commands have changed from Ruby's `bundle exec` to `go run`. diff --git a/docs/content/test/_index.md b/docs/content/test/_index.md new file mode 100644 index 000000000000..dee908f2aed5 --- /dev/null +++ b/docs/content/test/_index.md @@ -0,0 +1,4 @@ +--- +title: "Test" +weight: 40 +--- diff --git a/docs/content/develop/test/run-tests.md b/docs/content/test/run-tests.md similarity index 96% rename from docs/content/develop/test/run-tests.md rename to docs/content/test/run-tests.md index a75f38f81151..b818769d8095 100644 --- a/docs/content/develop/test/run-tests.md +++ b/docs/content/test/run-tests.md @@ -9,6 +9,7 @@ aliases: - /getting-started/run-provider-tests - /getting-started/use-built-provider - /develop/run-tests + - /develop/test/run-tests --- # Run tests @@ -118,7 +119,7 @@ aliases: - `After applying this test step, the plan was not empty.` - See [Fix diffs]({{< ref "/develop/diffs" >}}). - `Blocks of type "FIELD_NAME" are not expected here` - - The field does not exist; this is either because it has not been implemented or because the test is running for the `google` provider and the field is only implemented in the `google-beta` provider. See [Add resource tests]({{< ref "/develop/test/test" >}}) for information on using version guards to exclude beta-only fields from GA tests, or [Promote from beta to GA]({{< ref "/develop/promote-to-ga" >}}) for information on how to promote fields that were accidentally made beta-only. + - The field does not exist; this is either because it has not been implemented or because the test is running for the `google` provider and the field is only implemented in the `google-beta` provider. See [Add resource tests]({{< ref "/test/test" >}}) for information on using version guards to exclude beta-only fields from GA tests, or [Promote from beta to GA]({{< ref "/develop/promote-to-ga" >}}) for information on how to promote fields that were accidentally made beta-only. ## Optional: Test with different `terraform` versions @@ -134,7 +135,7 @@ Tests will use whatever version of the `terraform` binary is found on your `PATH Replace `VERSION` with the version you want to test. -1. Run automated tests following the [earlier section]({{< ref "/develop/test/run-tests#run-automated-tests" >}}). +1. Run automated tests following the [earlier section]({{< ref "/test/run-tests#run-automated-tests" >}}). ## Optional: Test manually @@ -296,4 +297,5 @@ To stop using developer overrides, stop setting `TF_CLI_CONFIG_FILE` in the comm Terraform will resume its normal behaviour of pulling published provider versions from the public Registry. Any version constraints in your Terraform configuration will come back into effect. Also, you may need to run `terraform init` to download the required version of the provider into your project directory if you haven't already. ## What's next? -- [Create a pull request]({{< ref "/contribute/create-pr" >}}) + +[Create a pull request]({{< ref "/contribute/create-pr" >}}) diff --git a/docs/content/develop/test/test.md b/docs/content/test/test.md similarity index 75% rename from docs/content/develop/test/test.md rename to docs/content/test/test.md index 3e77aa9f5b7a..47a2ebe04273 100644 --- a/docs/content/develop/test/test.md +++ b/docs/content/test/test.md @@ -9,6 +9,7 @@ aliases: - /how-to/add-handwritten-test - /develop/add-handwritten-test - /develop/test + - /develop/test/test --- # Add resource tests @@ -95,12 +96,12 @@ A create test is a test that creates the target resource and immediately destroy - Add `min_version: 'beta'` to the `examples` block in `RESOURCE_NAME.yaml`. {{< /tab >}} {{< tab "Handwritten" >}} -This section assumes you've used the [Add a resource]({{< ref "/develop/resource.md" >}}) guide to create your handwritten resource, and you have a working MMv1 config. +This section assumes you've used the [Add a resource]({{< ref "/develop/add-resource" >}}) guide to create your handwritten resource, and you have a working MMv1 config. > **Note:** If not, you can create one now, or skip this guide and construct the test by hand. Writing tests by hand can sometimes be a better option if there is a similar test you can copy from. 1. Add the test in MMv1. Repeat for all the create tests you will need. -2. [Generate the beta provider]({{< ref "/develop/generate-providers.md" >}}). +2. [Generate the beta provider]({{< ref "/develop/generate-providers" >}}). 3. From the beta provider, copy and paste the generated `*_generated_test.go` file into the appropriate service folder inside [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/) as a new file call `*_test.go`. 4. Modify the tests as needed. - Replace all occurrences of `github.com/hashicorp/terraform-provider-google-beta/google-beta` with `github.com/hashicorp/terraform-provider-google/google` @@ -240,8 +241,8 @@ An update test is a test that creates the target resource and then makes updates ## Add unit tests A unit test verifies functionality that is not related to interactions with the API, such as -[diff suppress functions]({{}}), -[validation functions]({{}}), +[diff suppress functions]({{}}), +[validation functions]({{}}), CustomizeDiff functions, and so on. Unit tests should be added to the appropriate folder in [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) in the file called `resource_PRODUCT_RESOURCE_test.go`. (You may need to create this file if it does not already exist. Replace PRODUCT with the product name and RESOURCE with the resource name; it should match the name of the generated resource file.) @@ -272,6 +273,59 @@ func TestSignatureAlgorithmDiffSuppress(t *testing.T) { } ``` +## Skip tests in VCR replaying mode + +Acceptance tests are run in VCR replaying mode on PRs (using pre-recorded HTTP requests and responses) to reduce the time it takes to present results to contributors. However, not all resources or tests are possible to run in replaying mode. Incompatible tests should be skipped during VCR replaying mode. They will still run in our nightly test suite. + +{{< tabs "skipping-tests-in-vcr-replaying" >}} + + {{< tab "Skip a generated test" >}} + Skipping acceptance tests that are generated from example files can be achieved by adding `skip_vcr: true` in the example's YAML: + + ```yaml + examples: + - name: 'bigtable_app_profile_anycluster' + ... + + # bigtable instance does not use the shared HTTP client, this test creates an instance + skip_vcr: true + ``` + + If you skip a test in VCR mode, include a code comment explaining the reason for skipping (for example, a link to a GitHub issue.) + + {{< /tab >}} + {{< tab "Skip a handwritten test" >}} + Skipping acceptance tests that are handwritten can be achieved by adding `acctest.SkipIfVcr(t)` at the start of the test: + + ```go + func TestAccPubsubTopic_update(t *testing.T) { + acctest.SkipIfVcr(t) // See: https://github.com/hashicorp/terraform-provider-google/issues/9999 + acctest.VcrTest(t, resource.TestCase{ ... } + } + ``` + + If you skip a test in VCR mode, include a code comment explaining the reason for skipping (for example, a link to a GitHub issue.) + + {{< /tab >}} +{{< /tabs >}} + +### Reasons that tests are skipped in VCR replaying mode + +| Problem | How to fix/Other info | Skip in VCR replaying? | +| ------------------------------------------------ | ---------------------- |------------- | +| *Incorrect or insufficient data is present in VCR recordings to replay tests*. Tests will fail with `Requested interaction not found` errors during REPLAYING mode | Make sure that you're not introducing randomness into the test, e.g. by unnecessarily using the random provider to set a resource's name.| If you cannot avoid this issue you should skip the test, but try to ensure that it cannot be fixed first.| +*Bigtable acceptance tests aren't working in VCR mode*. `Requested interaction not found` errors are seen during Bigtable tests run in REPLAYING mode | Currently the provider uses a separate client than the rest of the provider to interact with the Bigtable API. As HTTP traffic to the Bigtable API doesn't go via the shared client it cannot be recorded in RECORDING mode.| Skip the test in VCR for Bigtable. | +| *Using multiple provider aliases doesn't work in VCR*. You may have two instances of the google provider in the test config but one of them doesn't seem to be using its provider arguments - for example, using the wrong default project. | See this GitHub issue: https://github.com/hashicorp/terraform-provider-google/issues/20019 . The problem is that, due to how the VCR system works, one provider instance will be configured and the other will be forced to reuse the first instance's configuration, despite them being given different provider arguments. | Skip the test in VCR is using aliases is unavoidable. | +| *Using multiple versions of the google/google-beta provider in a single test isn't working in VCR*. Unexpected test failures may occur during tests in REPLAYING mode where `ExternalProviders` is used to pull in past versions of the google/google-beta provider. | When ExternalProviders is used to pulling in other versions of the provider, any HTTP traffic through the external provider will not be recorded. If the HTTP traffic produces an unexpected result or returns an API error then the test will fail in REPLAYING mode. | Skip the test in VCR when testing the current provider behaviour versus previous released versions. | + +Some additional things to bear in mind are that VCR tests in REPLAYING mode will still interact with GCP APIs somewhat. For example: + +- When the provider is configured it will use credentials to obtain access tokens from GCP +- Some acceptance tests use bootstrapping functions that ensure long-lived resources are present in a testing project before the provider is tested. + +These tests can still run in VCR replaying mode; however, REPLAYING mode can't be used as a way to completely avoid HTTP traffic generally or with GCP APIs. + + ## What's next? -- [Run your tests]({{< ref "/develop/test/run-tests" >}}) +[Run your tests]({{< ref "/test/run-tests" >}}) diff --git a/mmv1/main.go b/mmv1/main.go index 62bfa6cef684..0db8a11238fc 100644 --- a/mmv1/main.go +++ b/mmv1/main.go @@ -323,6 +323,8 @@ func setProvider(forceProvider, version string, productApi *api.Product, startTi return provider.NewTerraformGoogleConversion(productApi, version, startTime) case "tgc_cai2hcl": return provider.NewCaiToTerraformConversion(productApi, version, startTime) + case "tgc_v6": + return provider.NewTerraformGoogleConversionV6(productApi, version, startTime) case "oics": return provider.NewTerraformOiCS(productApi, version, startTime) default: diff --git a/mmv1/products/accesscontextmanager/AccessLevel.yaml b/mmv1/products/accesscontextmanager/AccessLevel.yaml index f18ee80cf48e..98ddda93908f 100644 --- a/mmv1/products/accesscontextmanager/AccessLevel.yaml +++ b/mmv1/products/accesscontextmanager/AccessLevel.yaml @@ -51,14 +51,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/access_level_never_send_parent.go.tmpl' custom_import: 'templates/terraform/custom_import/set_access_policy_parent_from_self_link.go.tmpl' @@ -281,7 +275,7 @@ properties: required: true - name: 'vpcIpSubnetworks' type: Array - description: 'CIDR block IP subnetwork specification. Must be IPv4.' + description: 'A list of CIDR block IP subnetwork specification. Must be IPv4.' item_type: type: String min_size: 1 diff --git a/mmv1/products/accesscontextmanager/AccessLevels.yaml b/mmv1/products/accesscontextmanager/AccessLevels.yaml index 594588b2f1e1..45fbc20fc3c7 100644 --- a/mmv1/products/accesscontextmanager/AccessLevels.yaml +++ b/mmv1/products/accesscontextmanager/AccessLevels.yaml @@ -47,14 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_delete: 'templates/terraform/custom_delete/replace_all_access_levels_empty_list.go.tmpl' custom_import: 'templates/terraform/custom_import/set_access_policy_parent_from_access_policy.go.tmpl' diff --git a/mmv1/products/accesscontextmanager/AccessPolicy.yaml b/mmv1/products/accesscontextmanager/AccessPolicy.yaml index d554c8d05ebc..ef331b7d7fa4 100644 --- a/mmv1/products/accesscontextmanager/AccessPolicy.yaml +++ b/mmv1/products/accesscontextmanager/AccessPolicy.yaml @@ -47,14 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' diff --git a/mmv1/products/accesscontextmanager/AuthorizedOrgsDesc.yaml b/mmv1/products/accesscontextmanager/AuthorizedOrgsDesc.yaml index c9cf4c94c9d9..27d5807fae9f 100644 --- a/mmv1/products/accesscontextmanager/AuthorizedOrgsDesc.yaml +++ b/mmv1/products/accesscontextmanager/AuthorizedOrgsDesc.yaml @@ -47,14 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/access_level_never_send_parent.go.tmpl' post_create: 'templates/terraform/post_create/sleep_2_min.go.tmpl' diff --git a/mmv1/products/accesscontextmanager/EgressPolicy.yaml b/mmv1/products/accesscontextmanager/EgressPolicy.yaml index 5e60dd9e25ab..f7cf7a82d013 100644 --- a/mmv1/products/accesscontextmanager/EgressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/EgressPolicy.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - resource nested_query: diff --git a/mmv1/products/accesscontextmanager/GcpUserAccessBinding.yaml b/mmv1/products/accesscontextmanager/GcpUserAccessBinding.yaml index 0c07c39a9e92..9696adb5e577 100644 --- a/mmv1/products/accesscontextmanager/GcpUserAccessBinding.yaml +++ b/mmv1/products/accesscontextmanager/GcpUserAccessBinding.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/set_id_name_with_slashes.go.tmpl' exclude_tgc: true diff --git a/mmv1/products/accesscontextmanager/IngressPolicy.yaml b/mmv1/products/accesscontextmanager/IngressPolicy.yaml index 8e8415be80ca..84395d6d6ff4 100644 --- a/mmv1/products/accesscontextmanager/IngressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/IngressPolicy.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - resource nested_query: diff --git a/mmv1/products/accesscontextmanager/ServicePerimeter.yaml b/mmv1/products/accesscontextmanager/ServicePerimeter.yaml index 8ca2e4ae5f81..6981e3369fe3 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeter.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeter.yaml @@ -60,17 +60,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/access_context_manager.go.tmpl' encoder: 'templates/terraform/encoders/access_level_never_send_parent.go.tmpl' + pre_update: 'templates/terraform/pre_update/access_context_manager_service_perimeter.go.tmpl' custom_import: 'templates/terraform/custom_import/set_access_policy_parent_from_self_link.go.tmpl' # Skipping the sweeper due to the non-standard base_url exclude_sweeper: true @@ -257,7 +252,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -380,7 +375,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'sources' type: Array description: 'Sources that this EgressPolicy authorizes access from.' @@ -571,7 +566,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -689,7 +684,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'sources' type: Array description: 'Sources that this EgressPolicy authorizes access from.' @@ -788,3 +783,10 @@ properties: actually enforcing them. This testing is done through analyzing the differences between currently enforced and suggested restrictions. useExplicitDryRunSpec must bet set to True if any of the fields in the spec are set to non-default values. + - name: 'etag' + type: Fingerprint + description: | + An opaque identifier for the current version of the ServicePerimeter. This + identifier does not follow any specific format. If an etag is not provided, the + operation will be performed as if a valid etag is provided. + output: true diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunEgressPolicy.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunEgressPolicy.yaml index 2def63b66f4f..d445ef4d1de2 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunEgressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunEgressPolicy.yaml @@ -27,6 +27,9 @@ description: | ~> **Note:** By default, updates to this resource will remove the EgressPolicy from the from the perimeter and add it back in a non-atomic manner. To ensure that the new EgressPolicy is added before the old one is removed, add a `lifecycle` block with `create_before_destroy = true` to this resource. + ~> **Note:** If this resource is used alongside a `google_access_context_manager_service_perimeter` resource, + the service perimeter resource must have a `lifecycle` block with `ignore_changes = [spec[0].egress_policies]` so + they don't fight over which egress rules should be in the policy. references: guides: 'Guide to Ingress and Egress Rules': 'https://cloud.google.com/vpc-service-controls/docs/ingress-egress-rules' @@ -54,14 +57,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - egressFrom - egressTo @@ -108,7 +105,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -149,7 +146,7 @@ properties: then this `EgressTo` rule will authorize access to all resources outside the perimeter. custom_flatten: templates/terraform/custom_flatten/accesscontextmanager_egress_policy_resources_custom_flatten.go.tmpl - diff_suppress_func: AccessContextManagerServicePerimeterDryRunEgressPolicyEgressToResourcesDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterDryRunEgressPolicyEgressToResourcesDiffSuppressFunc item_type: type: String - name: 'externalResources' diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunIngressPolicy.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunIngressPolicy.yaml index d012a7986984..6bcbc88f3208 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunIngressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunIngressPolicy.yaml @@ -28,6 +28,9 @@ description: | ~> **Note:** By default, updates to this resource will remove the IngressPolicy from the from the perimeter and add it back in a non-atomic manner. To ensure that the new IngressPolicy is added before the old one is removed, add a `lifecycle` block with `create_before_destroy = true` to this resource. + ~> **Note:** If this resource is used alongside a `google_access_context_manager_service_perimeter` resource, + the service perimeter resource must have a `lifecycle` block with `ignore_changes = [spec[0].ingress_policies]` so + they don't fight over which ingress rules should be in the policy. references: guides: 'Guide to Ingress and Egress Rules': 'https://cloud.google.com/vpc-service-controls/docs/ingress-egress-rules' @@ -55,14 +58,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - ingressFrom - ingressTo @@ -110,7 +107,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -166,7 +163,7 @@ properties: resources inside the perimeter, provided that the request also matches the `operations` field. custom_flatten: templates/terraform/custom_flatten/accesscontextmanager_ingress_policy_resources_custom_flatten.go.tmpl - diff_suppress_func: AccessContextManagerServicePerimeterDryRunIngressPolicyIngressToResourcesDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterDryRunIngressPolicyIngressToResourcesDiffSuppressFunc item_type: type: String - name: 'operations' diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunResource.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunResource.yaml index 8a92f31380b0..c3c08c388ed8 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterDryRunResource.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterDryRunResource.yaml @@ -56,14 +56,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - resource nested_query: diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterEgressPolicy.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterEgressPolicy.yaml index aa134684c045..af0bc9923e1b 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterEgressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterEgressPolicy.yaml @@ -27,6 +27,9 @@ description: | ~> **Note:** By default, updates to this resource will remove the EgressPolicy from the from the perimeter and add it back in a non-atomic manner. To ensure that the new EgressPolicy is added before the old one is removed, add a `lifecycle` block with `create_before_destroy = true` to this resource. + ~> **Note:** If this resource is used alongside a `google_access_context_manager_service_perimeter` resource, + the service perimeter resource must have a `lifecycle` block with `ignore_changes = [status[0].egress_policies]` so + they don't fight over which egress rules should be in the policy. references: guides: 'Guide to Ingress and Egress Rules': 'https://cloud.google.com/vpc-service-controls/docs/ingress-egress-rules' @@ -54,14 +57,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - egressFrom - egressTo @@ -105,7 +102,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -147,7 +144,7 @@ properties: then this `EgressTo` rule will authorize access to all resources outside the perimeter. custom_flatten: templates/terraform/custom_flatten/accesscontextmanager_egress_policy_resources_custom_flatten.go.tmpl - diff_suppress_func: AccessContextManagerServicePerimeterEgressPolicyEgressToResourcesDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterEgressPolicyEgressToResourcesDiffSuppressFunc item_type: type: String - name: 'externalResources' diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterIngressPolicy.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterIngressPolicy.yaml index 4512d903033a..c17a75211fde 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterIngressPolicy.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterIngressPolicy.yaml @@ -28,6 +28,9 @@ description: | ~> **Note:** By default, updates to this resource will remove the IngressPolicy from the from the perimeter and add it back in a non-atomic manner. To ensure that the new IngressPolicy is added before the old one is removed, add a `lifecycle` block with `create_before_destroy = true` to this resource. + ~> **Note:** If this resource is used alongside a `google_access_context_manager_service_perimeter` resource, + the service perimeter resource must have a `lifecycle` block with `ignore_changes = [status[0].ingress_policies]` so + they don't fight over which ingress rules should be in the policy. references: guides: 'Guide to Ingress and Egress Rules': 'https://cloud.google.com/vpc-service-controls/docs/ingress-egress-rules' @@ -55,14 +58,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - ingressFrom - ingressTo @@ -107,7 +104,7 @@ properties: - 'ANY_IDENTITY' - 'ANY_USER_ACCOUNT' - 'ANY_SERVICE_ACCOUNT' - diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc - name: 'identities' type: Array description: | @@ -166,7 +163,7 @@ properties: resources inside the perimeter, provided that the request also matches the `operations` field. custom_flatten: templates/terraform/custom_flatten/accesscontextmanager_ingress_policy_resources_custom_flatten.go.tmpl - diff_suppress_func: AccessContextManagerServicePerimeterIngressPolicyIngressToResourcesDiffSupressFunc + diff_suppress_func: AccessContextManagerServicePerimeterIngressPolicyIngressToResourcesDiffSuppressFunc item_type: type: String - name: 'operations' diff --git a/mmv1/products/accesscontextmanager/ServicePerimeterResource.yaml b/mmv1/products/accesscontextmanager/ServicePerimeterResource.yaml index a748daef0d74..b20f9974080f 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeterResource.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeterResource.yaml @@ -56,14 +56,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - resource nested_query: diff --git a/mmv1/products/accesscontextmanager/ServicePerimeters.yaml b/mmv1/products/accesscontextmanager/ServicePerimeters.yaml index 0d0c4e97a441..7f77cb8333fc 100644 --- a/mmv1/products/accesscontextmanager/ServicePerimeters.yaml +++ b/mmv1/products/accesscontextmanager/ServicePerimeters.yaml @@ -42,14 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_delete: 'templates/terraform/custom_delete/replace_all_service_perimeters_empty_list.go.tmpl' custom_import: 'templates/terraform/custom_import/set_access_policy_parent_from_access_policy.go.tmpl' @@ -100,6 +94,13 @@ properties: description: | Description of the ServicePerimeter and its use. Does not affect behavior. + - name: 'etag' + type: Fingerprint + description: | + An opaque identifier for the current version of the ServicePerimeter. This + identifier does not follow any specific format. If an etag is not provided, the + operation will be performed as if a valid etag is provided. + output: true - name: 'createTime' type: Time description: | diff --git a/mmv1/products/accesscontextmanager/product.yaml b/mmv1/products/accesscontextmanager/product.yaml index 0bd2aa6284d2..004460a95763 100644 --- a/mmv1/products/accesscontextmanager/product.yaml +++ b/mmv1/products/accesscontextmanager/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/activedirectory/Domain.yaml b/mmv1/products/activedirectory/Domain.yaml index c2eacccf80f7..a93829d63221 100644 --- a/mmv1/products/activedirectory/Domain.yaml +++ b/mmv1/products/activedirectory/Domain.yaml @@ -41,19 +41,13 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 # It takes about 35-40 mins to get the resource created timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_delete: 'templates/terraform/pre_delete/active_directory_domain.go.tmpl' custom_import: 'templates/terraform/custom_import/self_link_as_name.tmpl' diff --git a/mmv1/products/activedirectory/DomainTrust.yaml b/mmv1/products/activedirectory/DomainTrust.yaml index 45a20a175ce8..93771ad0c432 100644 --- a/mmv1/products/activedirectory/DomainTrust.yaml +++ b/mmv1/products/activedirectory/DomainTrust.yaml @@ -42,14 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - targetDomainName nested_query: diff --git a/mmv1/products/activedirectory/Peering.yaml b/mmv1/products/activedirectory/Peering.yaml index 10e7abe51aeb..79a9742d56f2 100644 --- a/mmv1/products/activedirectory/Peering.yaml +++ b/mmv1/products/activedirectory/Peering.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'active_directory_peering_basic' diff --git a/mmv1/products/alloydb/Cluster.yaml b/mmv1/products/alloydb/Cluster.yaml index ad5967241524..65645b3d8089 100644 --- a/mmv1/products/alloydb/Cluster.yaml +++ b/mmv1/products/alloydb/Cluster.yaml @@ -39,27 +39,21 @@ import_format: - 'projects/{{project}}/locations/{{location}}/clusters/{{cluster_id}}' - '{{cluster_id}}' timeouts: - insert_minutes: 30 - update_minutes: 30 - delete_minutes: 30 + insert_minutes: 120 + update_minutes: 120 + delete_minutes: 120 autogen_async: true async: actions: ['create', 'delete', 'update'] type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: - insert_minutes: 30 - update_minutes: 30 - delete_minutes: 30 + insert_minutes: 120 + update_minutes: 120 + delete_minutes: 120 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/alloydb_cluster.go.tmpl' pre_update: 'templates/terraform/pre_update/alloydb_cluster.go.tmpl' diff --git a/mmv1/products/alloydb/Instance.yaml b/mmv1/products/alloydb/Instance.yaml index 3cad8a5b6865..48365683430b 100644 --- a/mmv1/products/alloydb/Instance.yaml +++ b/mmv1/products/alloydb/Instance.yaml @@ -39,18 +39,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 120 update_minutes: 120 delete_minutes: 120 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: pre_create: 'templates/terraform/pre_create/alloydb_instance.go.tmpl' diff --git a/mmv1/products/apigateway/Api.yaml b/mmv1/products/apigateway/Api.yaml index 883e796621fb..6695e84edfca 100644 --- a/mmv1/products/apigateway/Api.yaml +++ b/mmv1/products/apigateway/Api.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - apiId iam_policy: diff --git a/mmv1/products/apigateway/ApiConfig.yaml b/mmv1/products/apigateway/ApiConfig.yaml index 5ec9f9dbf972..f879d73564aa 100644 --- a/mmv1/products/apigateway/ApiConfig.yaml +++ b/mmv1/products/apigateway/ApiConfig.yaml @@ -41,14 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - apiConfigId iam_policy: diff --git a/mmv1/products/apigateway/Gateway.yaml b/mmv1/products/apigateway/Gateway.yaml index 29320f100073..2c8b6460094d 100644 --- a/mmv1/products/apigateway/Gateway.yaml +++ b/mmv1/products/apigateway/Gateway.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - gatewayId iam_policy: diff --git a/mmv1/products/apigateway/product.yaml b/mmv1/products/apigateway/product.yaml index c656d1cad15e..4b705e9246ee 100644 --- a/mmv1/products/apigateway/product.yaml +++ b/mmv1/products/apigateway/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/apigee/AddonsConfig.yaml b/mmv1/products/apigee/AddonsConfig.yaml index 1955f61e4a54..7a23d261e204 100644 --- a/mmv1/products/apigee/AddonsConfig.yaml +++ b/mmv1/products/apigee/AddonsConfig.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/apigee_addons.go.tmpl' test_check_destroy: 'templates/terraform/custom_check_destroy/apigee_addons_override.go.tmpl' diff --git a/mmv1/products/apigee/AppGroup.yaml b/mmv1/products/apigee/AppGroup.yaml index afaf6cee14c1..ae0f14f69a6a 100644 --- a/mmv1/products/apigee/AppGroup.yaml +++ b/mmv1/products/apigee/AppGroup.yaml @@ -79,7 +79,7 @@ properties: - name: "channelId" type: String description: | - Channel identifier identifies the owner maintaing this grouping. + Channel identifier identifies the owner maintaining this grouping. - name: "displayName" type: String description: | diff --git a/mmv1/products/apigee/Developer.yaml b/mmv1/products/apigee/Developer.yaml index e26a5ee6593e..da0a8d8f040e 100644 --- a/mmv1/products/apigee/Developer.yaml +++ b/mmv1/products/apigee/Developer.yaml @@ -44,6 +44,7 @@ examples: billing_account: "BILLING_ACCT" exclude_docs: true skip_vcr: true + external_providers: ["time"] - name: "apigee_developer_with_attributes" vars: instance_name: "my-instance" @@ -56,6 +57,7 @@ examples: billing_account: "BILLING_ACCT" exclude_docs: true skip_vcr: true + external_providers: ["time"] parameters: - name: "orgId" type: String diff --git a/mmv1/products/apigee/EndpointAttachment.yaml b/mmv1/products/apigee/EndpointAttachment.yaml index 1efb05ec209d..26376d98e377 100644 --- a/mmv1/products/apigee/EndpointAttachment.yaml +++ b/mmv1/products/apigee/EndpointAttachment.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/apigee_endpoint_attachment.go.tmpl' exclude_sweeper: true diff --git a/mmv1/products/apigee/EnvKeystore.yaml b/mmv1/products/apigee/EnvKeystore.yaml index 622f539bc2f3..b0dac4161f2a 100644 --- a/mmv1/products/apigee/EnvKeystore.yaml +++ b/mmv1/products/apigee/EnvKeystore.yaml @@ -47,6 +47,7 @@ examples: org_id: 'ORG_ID' billing_account: 'BILLING_ACCT' exclude_docs: true + external_providers: ["time"] parameters: - name: 'envId' type: String diff --git a/mmv1/products/apigee/Envgroup.yaml b/mmv1/products/apigee/Envgroup.yaml index c913be9f4b87..321cae6bb4e8 100644 --- a/mmv1/products/apigee/Envgroup.yaml +++ b/mmv1/products/apigee/Envgroup.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/apigee_environment_group.go.tmpl' examples: diff --git a/mmv1/products/apigee/EnvgroupAttachment.yaml b/mmv1/products/apigee/EnvgroupAttachment.yaml index 1934a6ef58fe..82c1b7e23e5e 100644 --- a/mmv1/products/apigee/EnvgroupAttachment.yaml +++ b/mmv1/products/apigee/EnvgroupAttachment.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/apigee_environment_group_attachment.go.tmpl' exclude_sweeper: true diff --git a/mmv1/products/apigee/Environment.yaml b/mmv1/products/apigee/Environment.yaml index 16275a2d9467..aadf685fb443 100644 --- a/mmv1/products/apigee/Environment.yaml +++ b/mmv1/products/apigee/Environment.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'env_id' @@ -74,6 +68,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_environment_basic_deployment_apiproxy_type_test' primary_resource_id: 'apigee_environment' primary_resource_name: 'fmt.Sprintf("organizations/tf-test%s", context["random_suffix"]), fmt.Sprintf("tf-test%s", context["random_suffix"])' @@ -83,6 +78,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_environment_patch_update_test' primary_resource_id: 'apigee_environment' primary_resource_name: 'fmt.Sprintf("organizations/tf-test%s", context["random_suffix"]), fmt.Sprintf("tf-test%s", context["random_suffix"])' @@ -93,6 +89,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] parameters: - name: 'orgId' type: String diff --git a/mmv1/products/apigee/Instance.yaml b/mmv1/products/apigee/Instance.yaml index 7af8975f474f..b99a1a95932f 100644 --- a/mmv1/products/apigee/Instance.yaml +++ b/mmv1/products/apigee/Instance.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/apigee_instance.go.tmpl' custom_import: 'templates/terraform/custom_import/apigee_instance.go.tmpl' @@ -69,6 +63,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_instance_cidr_range' vars: instance_name: 'my-instance-name' @@ -83,6 +78,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_instance_ip_range' vars: instance_name: 'my-instance-name' @@ -97,6 +93,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_instance_full' vars: instance_name: 'my-instance-name' @@ -112,6 +109,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_instance_service_attachment_basic_test' primary_resource_id: 'apigee_instance' test_env_vars: @@ -120,6 +118,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] parameters: - name: 'orgId' type: String diff --git a/mmv1/products/apigee/InstanceAttachment.yaml b/mmv1/products/apigee/InstanceAttachment.yaml index b6fde339e98a..1ae86f456e68 100644 --- a/mmv1/products/apigee/InstanceAttachment.yaml +++ b/mmv1/products/apigee/InstanceAttachment.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/apigee_instance_attachment.go.tmpl' # Skipping the sweeper due to the non-standard instance_id @@ -68,6 +62,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] parameters: - name: 'instanceId' type: String diff --git a/mmv1/products/apigee/NatAddress.yaml b/mmv1/products/apigee/NatAddress.yaml index 258265fc64d3..b70e73a66b59 100644 --- a/mmv1/products/apigee/NatAddress.yaml +++ b/mmv1/products/apigee/NatAddress.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/apigee_nat_address.go.tmpl' encoder: 'templates/terraform/encoders/apigee_nat_address.go.tmpl' diff --git a/mmv1/products/apigee/Organization.yaml b/mmv1/products/apigee/Organization.yaml index 05e38966e049..55db1fc16838 100644 --- a/mmv1/products/apigee/Organization.yaml +++ b/mmv1/products/apigee/Organization.yaml @@ -30,22 +30,16 @@ timeouts: delete_minutes: 45 autogen_async: true async: - actions: ['create', 'update'] + actions: ['create', 'delete', 'update'] type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 45 update_minutes: 45 delete_minutes: 45 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/apigee_organization.go.tmpl' custom_import: 'templates/terraform/custom_import/apigee_organization.go.tmpl' @@ -64,6 +58,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_organization_cloud_basic_disable_vpc_peering' exclude_test: true # This is a more verbose version of the above that creates all @@ -95,6 +90,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_organization_cloud_full_disable_vpc_peering' exclude_test: true # This is a more verbose version of the above that creates all @@ -112,6 +108,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_organization_retention_test' primary_resource_id: 'org' min_version: 'beta' @@ -121,6 +118,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] - name: 'apigee_organization_drz_test' primary_resource_id: 'org' min_version: 'beta' @@ -130,6 +128,7 @@ examples: exclude_docs: true # Resource creation race skip_vcr: true + external_providers: ["time"] parameters: - name: 'projectId' type: String diff --git a/mmv1/products/appengine/ApplicationUrlDispatchRules.yaml b/mmv1/products/appengine/ApplicationUrlDispatchRules.yaml index a797c2619853..22872fb006d0 100644 --- a/mmv1/products/appengine/ApplicationUrlDispatchRules.yaml +++ b/mmv1/products/appengine/ApplicationUrlDispatchRules.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: test_check_destroy: 'templates/terraform/custom_check_destroy/appengine.go.tmpl' exclude_sweeper: true diff --git a/mmv1/products/appengine/DomainMapping.yaml b/mmv1/products/appengine/DomainMapping.yaml index 4a097876a831..1e9995803021 100644 --- a/mmv1/products/appengine/DomainMapping.yaml +++ b/mmv1/products/appengine/DomainMapping.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: decoder: 'templates/terraform/decoders/app_engine_domain_mapping.go.tmpl' examples: diff --git a/mmv1/products/appengine/FlexibleAppVersion.yaml b/mmv1/products/appengine/FlexibleAppVersion.yaml index a930b9f85296..07f1cacf6a04 100644 --- a/mmv1/products/appengine/FlexibleAppVersion.yaml +++ b/mmv1/products/appengine/FlexibleAppVersion.yaml @@ -46,15 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'appengine#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'versions' custom_code: encoder: 'templates/terraform/encoders/flex_app_version.go.tmpl' diff --git a/mmv1/products/appengine/ServiceNetworkSettings.yaml b/mmv1/products/appengine/ServiceNetworkSettings.yaml index 1ee47e8fb9be..782846373738 100644 --- a/mmv1/products/appengine/ServiceNetworkSettings.yaml +++ b/mmv1/products/appengine/ServiceNetworkSettings.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'appengine#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: test_check_destroy: 'templates/terraform/custom_check_destroy/skip_delete_during_test.go.tmpl' examples: diff --git a/mmv1/products/appengine/ServiceSplitTraffic.yaml b/mmv1/products/appengine/ServiceSplitTraffic.yaml index 9ad2d5ca4566..fd169e0df58d 100644 --- a/mmv1/products/appengine/ServiceSplitTraffic.yaml +++ b/mmv1/products/appengine/ServiceSplitTraffic.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'appengine#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: test_check_destroy: 'templates/terraform/custom_check_destroy/skip_delete_during_test.go.tmpl' examples: diff --git a/mmv1/products/appengine/StandardAppVersion.yaml b/mmv1/products/appengine/StandardAppVersion.yaml index ebc4b99ac52a..e6d35a64b845 100644 --- a/mmv1/products/appengine/StandardAppVersion.yaml +++ b/mmv1/products/appengine/StandardAppVersion.yaml @@ -48,19 +48,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'appengine#operation' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 20 update_minutes: 20 delete_minutes: 20 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'versions' custom_code: custom_delete: 'templates/terraform/custom_delete/appversion_delete.go.tmpl' diff --git a/mmv1/products/apphub/Application.yaml b/mmv1/products/apphub/Application.yaml index dc932932af70..cde922521370 100644 --- a/mmv1/products/apphub/Application.yaml +++ b/mmv1/products/apphub/Application.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/apphub_application.go.tmpl' custom_diff: diff --git a/mmv1/products/apphub/Service.yaml b/mmv1/products/apphub/Service.yaml index 5b6a5084cc51..a7c59b3e9a36 100644 --- a/mmv1/products/apphub/Service.yaml +++ b/mmv1/products/apphub/Service.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'apphub_service_basic' diff --git a/mmv1/products/apphub/ServiceProjectAttachment.yaml b/mmv1/products/apphub/ServiceProjectAttachment.yaml index 8eb51ca7b9a2..c7ddfb3bbe08 100644 --- a/mmv1/products/apphub/ServiceProjectAttachment.yaml +++ b/mmv1/products/apphub/ServiceProjectAttachment.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/apphub_service_project.go.tmpl' examples: diff --git a/mmv1/products/apphub/Workload.yaml b/mmv1/products/apphub/Workload.yaml index 60b53e8de302..cdf4a131a8ad 100644 --- a/mmv1/products/apphub/Workload.yaml +++ b/mmv1/products/apphub/Workload.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'apphub_workload_basic' diff --git a/mmv1/products/artifactregistry/Repository.yaml b/mmv1/products/artifactregistry/Repository.yaml index 9c1b513f0892..6c79b2f1b783 100644 --- a/mmv1/products/artifactregistry/Repository.yaml +++ b/mmv1/products/artifactregistry/Repository.yaml @@ -27,7 +27,6 @@ update_verb: 'PATCH' update_mask: true import_format: - 'projects/{{project}}/locations/{{location}}/repositories/{{repository_id}}' - - '{{repository_id}}' timeouts: insert_minutes: 20 update_minutes: 20 @@ -38,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' allowed_iam_role: 'roles/artifactregistry.reader' @@ -68,6 +61,12 @@ examples: vars: repository_id: 'my-repository' desc: 'example docker repository' + - name: 'artifact_registry_repository_multi_region' + primary_resource_id: 'my-repo' + primary_resource_name: 'fmt.Sprintf("tf-test-my-repository%s", context["random_suffix"])' + vars: + repository_id: 'my-repository' + desc: 'example docker repository' - name: 'artifact_registry_repository_docker' primary_resource_id: 'my-repo' vars: @@ -209,15 +208,6 @@ examples: # response. - 'remote_repository_config.0.disable_upstream_validation' parameters: -properties: - - name: 'name' - type: String - description: |- - The name of the repository, for example: - "repo1" - output: true - custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' - custom_expand: 'templates/terraform/custom_expand/shortname_to_url.go.tmpl' - name: 'repository_id' type: String description: |- @@ -229,12 +219,26 @@ properties: custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' - name: 'location' type: String - description: | - The name of the location this repository is located in. + description: |- + The name of the repository's location. In addition to specific regions, + special values for multi-region locations are `asia`, `europe`, and `us`. + See [here](https://cloud.google.com/artifact-registry/docs/repositories/repo-locations), + or use the + [google_artifact_registry_locations](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/artifact_registry_locations) + data source for possible values. url_param_only: true required: false immutable: true default_from_api: true +properties: + - name: 'name' + type: String + description: |- + The name of the repository, for example: + "repo1" + output: true + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' + custom_expand: 'templates/terraform/custom_expand/shortname_to_url.go.tmpl' - name: 'format' type: String description: |- diff --git a/mmv1/products/artifactregistry/product.yaml b/mmv1/products/artifactregistry/product.yaml index c8c98003c1cd..bcbdcb394eb2 100644 --- a/mmv1/products/artifactregistry/product.yaml +++ b/mmv1/products/artifactregistry/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/backupdr/BackupVault.yaml b/mmv1/products/backupdr/BackupVault.yaml index a4239f08fb2f..f370888f3eef 100644 --- a/mmv1/products/backupdr/BackupVault.yaml +++ b/mmv1/products/backupdr/BackupVault.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: !ruby/object:Provider::Terraform::CustomCode pre_delete: 'templates/terraform/pre_delete/backup_dr_backup_vault.go.tmpl' diff --git a/mmv1/products/backupdr/ManagementServer.yaml b/mmv1/products/backupdr/ManagementServer.yaml index aaf860cdee8e..6e1fe62612e5 100644 --- a/mmv1/products/backupdr/ManagementServer.yaml +++ b/mmv1/products/backupdr/ManagementServer.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'backup_dr_management_server' diff --git a/mmv1/products/backupdr/product.yaml b/mmv1/products/backupdr/product.yaml index d668e8340ef9..4a72f271d356 100644 --- a/mmv1/products/backupdr/product.yaml +++ b/mmv1/products/backupdr/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/beyondcorp/AppConnection.yaml b/mmv1/products/beyondcorp/AppConnection.yaml index e6d6bfb68738..b18a67eae6ac 100644 --- a/mmv1/products/beyondcorp/AppConnection.yaml +++ b/mmv1/products/beyondcorp/AppConnection.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'beyondcorp_app_connection_basic' @@ -59,7 +53,6 @@ examples: account_id: 'my-account' app_connector_name: 'my-app-connector' app_connection_name: 'my-app-connection' - external_providers: ["time"] - name: 'beyondcorp_app_connection_full' primary_resource_id: 'app_connection' primary_resource_name: 'fmt.Sprintf("tf_test_my_app_connection%s", context["random_suffix"])' @@ -69,7 +62,6 @@ examples: app_connector_name: 'my-app-connector' app_connection_name: 'my-app-connection' display_name: 'some display name' - external_providers: ["time"] parameters: properties: - name: 'name' diff --git a/mmv1/products/beyondcorp/AppConnector.yaml b/mmv1/products/beyondcorp/AppConnector.yaml index 9bcc62c089c5..e6d813017782 100644 --- a/mmv1/products/beyondcorp/AppConnector.yaml +++ b/mmv1/products/beyondcorp/AppConnector.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'beyondcorp_app_connector_basic' diff --git a/mmv1/products/beyondcorp/AppGateway.yaml b/mmv1/products/beyondcorp/AppGateway.yaml index e228ec4b3999..9a39bc7b9318 100644 --- a/mmv1/products/beyondcorp/AppGateway.yaml +++ b/mmv1/products/beyondcorp/AppGateway.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 20 update_minutes: 20 delete_minutes: 20 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: schema_version: 1 state_upgraders: true diff --git a/mmv1/products/billingbudget/Budget.yaml b/mmv1/products/billingbudget/Budget.yaml index 54551074a0f0..133de3842ffd 100644 --- a/mmv1/products/billingbudget/Budget.yaml +++ b/mmv1/products/billingbudget/Budget.yaml @@ -213,7 +213,7 @@ properties: this is a list of credit types to be subtracted from gross cost to determine the spend for threshold calculations. See a list of acceptable credit type values. If creditTypesTreatment is not INCLUDE_SPECIFIED_CREDITS, this field must be empty. - **Note:** If the field has a value in the config and needs to be removed, the field has to be an emtpy array in the config. + **Note:** If the field has a value in the config and needs to be removed, the field has to be an empty array in the config. default_from_api: true at_least_one_of: - 'budget_filter.0.projects' @@ -236,7 +236,7 @@ properties: If the field is omitted, the report will include usage from the parent account and all subaccounts, if they exist. - **Note:** If the field has a value in the config and needs to be removed, the field has to be an emtpy array in the config. + **Note:** If the field has a value in the config and needs to be removed, the field has to be an empty array in the config. default_from_api: true at_least_one_of: - 'budget_filter.0.projects' diff --git a/mmv1/products/blockchainnodeengine/BlockchainNodes.yaml b/mmv1/products/blockchainnodeengine/BlockchainNodes.yaml index 1ce584deb9aa..43afc298cec6 100644 --- a/mmv1/products/blockchainnodeengine/BlockchainNodes.yaml +++ b/mmv1/products/blockchainnodeengine/BlockchainNodes.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'blockchain_nodes_basic' diff --git a/mmv1/products/certificatemanager/Certificate.yaml b/mmv1/products/certificatemanager/Certificate.yaml index 9f78e181c7aa..cbd76d526496 100644 --- a/mmv1/products/certificatemanager/Certificate.yaml +++ b/mmv1/products/certificatemanager/Certificate.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/cert_manager.tmpl' schema_version: 1 diff --git a/mmv1/products/certificatemanager/CertificateIssuanceConfig.yaml b/mmv1/products/certificatemanager/CertificateIssuanceConfig.yaml index 31c8f35909c9..b4d6e80504c6 100644 --- a/mmv1/products/certificatemanager/CertificateIssuanceConfig.yaml +++ b/mmv1/products/certificatemanager/CertificateIssuanceConfig.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: schema_version: 1 state_upgraders: true diff --git a/mmv1/products/certificatemanager/CertificateMap.yaml b/mmv1/products/certificatemanager/CertificateMap.yaml index 05b8281082f3..48b1f6fbb834 100644 --- a/mmv1/products/certificatemanager/CertificateMap.yaml +++ b/mmv1/products/certificatemanager/CertificateMap.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'certificate_manager_certificate_map_basic' diff --git a/mmv1/products/certificatemanager/CertificateMapEntry.yaml b/mmv1/products/certificatemanager/CertificateMapEntry.yaml index aaa6e9f12a96..a8b23152a365 100644 --- a/mmv1/products/certificatemanager/CertificateMapEntry.yaml +++ b/mmv1/products/certificatemanager/CertificateMapEntry.yaml @@ -32,14 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'certificate_manager_certificate_map_entry_full' diff --git a/mmv1/products/certificatemanager/DnsAuthorization.yaml b/mmv1/products/certificatemanager/DnsAuthorization.yaml index 5c0cd5a83485..36b53b8ac0ec 100644 --- a/mmv1/products/certificatemanager/DnsAuthorization.yaml +++ b/mmv1/products/certificatemanager/DnsAuthorization.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: schema_version: 1 state_upgraders: true diff --git a/mmv1/products/certificatemanager/TrustConfig.yaml b/mmv1/products/certificatemanager/TrustConfig.yaml index de5776b10f4e..7cff05cba687 100644 --- a/mmv1/products/certificatemanager/TrustConfig.yaml +++ b/mmv1/products/certificatemanager/TrustConfig.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'certificate_manager_trust_config' diff --git a/mmv1/products/cloudbuild/BitbucketServerConfig.yaml b/mmv1/products/cloudbuild/BitbucketServerConfig.yaml index 7dc1b77f1d52..a16fc8c7c4dd 100644 --- a/mmv1/products/cloudbuild/BitbucketServerConfig.yaml +++ b/mmv1/products/cloudbuild/BitbucketServerConfig.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/cloudbuild_bitbucketserver_config.go.tmpl' post_create: 'templates/terraform/post_create/cloudbuild_bitbucketserver_config.go.tmpl' diff --git a/mmv1/products/clouddeploy/Automation.yaml b/mmv1/products/clouddeploy/Automation.yaml index d2e82a60d497..4431164c4f3b 100644 --- a/mmv1/products/clouddeploy/Automation.yaml +++ b/mmv1/products/clouddeploy/Automation.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'clouddeploy_automation_basic' diff --git a/mmv1/products/clouddeploy/CustomTargetType.yaml b/mmv1/products/clouddeploy/CustomTargetType.yaml index 3f7368ffe4b4..1034fcf7fe1f 100644 --- a/mmv1/products/clouddeploy/CustomTargetType.yaml +++ b/mmv1/products/clouddeploy/CustomTargetType.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' diff --git a/mmv1/products/clouddomains/Registration.yaml b/mmv1/products/clouddomains/Registration.yaml index c641c5cf7568..dfbe33a6f161 100644 --- a/mmv1/products/clouddomains/Registration.yaml +++ b/mmv1/products/clouddomains/Registration.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/clouddomains_registration.go.tmpl' encoder: 'templates/terraform/encoders/clouddomains_registration.go.tmpl' diff --git a/mmv1/products/cloudfunctions/CloudFunction.yaml b/mmv1/products/cloudfunctions/CloudFunction.yaml index e09afc57d7ed..d6b3a7b4cfa1 100644 --- a/mmv1/products/cloudfunctions/CloudFunction.yaml +++ b/mmv1/products/cloudfunctions/CloudFunction.yaml @@ -32,14 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' collection_url_key: 'functions' iam_policy: method_name_separator: ':' diff --git a/mmv1/products/cloudfunctions2/Function.yaml b/mmv1/products/cloudfunctions2/Function.yaml index bc32e810632d..966dfbba3520 100644 --- a/mmv1/products/cloudfunctions2/Function.yaml +++ b/mmv1/products/cloudfunctions2/Function.yaml @@ -38,19 +38,13 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 # It takes about 35-40 mins to get the resource created timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'cloud_function' @@ -593,7 +587,7 @@ properties: - name: 'projectId' type: String description: | - Project identifier (preferrably project number but can also be the project ID) of the project that contains the secret. If not set, it will be populated with the function's project assuming that the secret exists in the same project as of the function. + Project identifier (preferably project number but can also be the project ID) of the project that contains the secret. If not set, it will be populated with the function's project assuming that the secret exists in the same project as of the function. required: true - name: 'secret' type: String @@ -619,7 +613,7 @@ properties: - name: 'projectId' type: String description: | - Project identifier (preferrably project number but can also be the project ID) of the project that contains the secret. If not set, it will be populated with the function's project assuming that the secret exists in the same project as of the function. + Project identifier (preferably project number but can also be the project ID) of the project that contains the secret. If not set, it will be populated with the function's project assuming that the secret exists in the same project as of the function. required: true - name: 'secret' type: String diff --git a/mmv1/products/cloudids/Endpoint.yaml b/mmv1/products/cloudids/Endpoint.yaml index 11076d3f7e30..68c34fd53e3e 100644 --- a/mmv1/products/cloudids/Endpoint.yaml +++ b/mmv1/products/cloudids/Endpoint.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 2000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: exclude_sweeper: true examples: diff --git a/mmv1/products/cloudids/product.yaml b/mmv1/products/cloudids/product.yaml index bd3761940ce6..d9606517cc0b 100644 --- a/mmv1/products/cloudids/product.yaml +++ b/mmv1/products/cloudids/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 2000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/cloudrunv2/Job.yaml b/mmv1/products/cloudrunv2/Job.yaml index 0d21b6eb5956..211134f50272 100644 --- a/mmv1/products/cloudrunv2/Job.yaml +++ b/mmv1/products/cloudrunv2/Job.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' @@ -198,7 +192,7 @@ properties: - name: 'expireTime' type: Time description: |- - For a deleted resource, the time after which it will be permamently deleted. + For a deleted resource, the time after which it will be permanently deleted. output: true - name: 'creator' type: String diff --git a/mmv1/products/cloudrunv2/Service.yaml b/mmv1/products/cloudrunv2/Service.yaml index 38b8dc966d88..7f50e7cf4d2f 100644 --- a/mmv1/products/cloudrunv2/Service.yaml +++ b/mmv1/products/cloudrunv2/Service.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' @@ -245,7 +239,7 @@ properties: - name: 'expireTime' type: Time description: |- - For a deleted resource, the time after which it will be permamently deleted. + For a deleted resource, the time after which it will be permanently deleted. output: true - name: 'creator' type: String diff --git a/mmv1/products/composer/UserWorkloadsConfigMap.yaml b/mmv1/products/composer/UserWorkloadsConfigMap.yaml index 9835430077f0..4efc7c9ec7fe 100644 --- a/mmv1/products/composer/UserWorkloadsConfigMap.yaml +++ b/mmv1/products/composer/UserWorkloadsConfigMap.yaml @@ -16,11 +16,9 @@ name: 'UserWorkloadsConfigMap' description: | User workloads ConfigMap used by Airflow tasks that run with Kubernetes Executor or KubernetesPodOperator. Intended for Composer 3 Environments. -min_version: 'beta' references: guides: - # TODO: add v1 reference when this is moved to ga - api: 'https://cloud.google.com/composer/docs/reference/rest/v1beta1/projects.locations.environments.userWorkloadsConfigMaps' + api: 'https://cloud.google.com/composer/docs/reference/rest/v1/projects.locations.environments.userWorkloadsConfigMaps' docs: base_url: 'projects/{{project}}/locations/{{region}}/environments/{{environment}}/userWorkloadsConfigMaps' self_link: 'projects/{{project}}/locations/{{region}}/environments/{{environment}}/userWorkloadsConfigMaps/{{name}}' @@ -41,7 +39,6 @@ parameters: type: String description: | The location or Compute Engine region for the environment. - min_version: 'beta' url_param_only: true immutable: true default_from_api: true @@ -49,7 +46,6 @@ parameters: type: String description: | Environment where the Kubernetes ConfigMap will be stored and used. - min_version: 'beta' url_param_only: true required: true immutable: true @@ -60,7 +56,6 @@ properties: type: String description: | Name of the Kubernetes ConfigMap. - min_version: 'beta' required: true immutable: true custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' @@ -72,5 +67,4 @@ properties: description: | The "data" field of Kubernetes ConfigMap, organized in key-value pairs. For details see: https://kubernetes.io/docs/concepts/configuration/configmap/ - min_version: 'beta' immutable: false diff --git a/mmv1/products/compute/Address.yaml b/mmv1/products/compute/Address.yaml index a65b502166f7..a5df36000b4b 100644 --- a/mmv1/products/compute/Address.yaml +++ b/mmv1/products/compute/Address.yaml @@ -46,15 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: post_create: 'templates/terraform/post_create/labels.tmpl' diff --git a/mmv1/products/compute/Autoscaler.yaml b/mmv1/products/compute/Autoscaler.yaml index b8dadbe531b0..cc2c3309eb00 100644 --- a/mmv1/products/compute/Autoscaler.yaml +++ b/mmv1/products/compute/Autoscaler.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/BackendBucket.yaml b/mmv1/products/compute/BackendBucket.yaml index 400b44bf1986..b4fa8f22af04 100644 --- a/mmv1/products/compute/BackendBucket.yaml +++ b/mmv1/products/compute/BackendBucket.yaml @@ -38,15 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: parent_resource_attribute: 'name' diff --git a/mmv1/products/compute/BackendBucketSignedUrlKey.yaml b/mmv1/products/compute/BackendBucketSignedUrlKey.yaml index 72408dcecb83..ebd5860be4cf 100644 --- a/mmv1/products/compute/BackendBucketSignedUrlKey.yaml +++ b/mmv1/products/compute/BackendBucketSignedUrlKey.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/BackendService.yaml b/mmv1/products/compute/BackendService.yaml index 609bc63c1f60..099e09893b39 100644 --- a/mmv1/products/compute/BackendService.yaml +++ b/mmv1/products/compute/BackendService.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.admin' diff --git a/mmv1/products/compute/BackendServiceSignedUrlKey.yaml b/mmv1/products/compute/BackendServiceSignedUrlKey.yaml index 95097bc60922..f10649f7d184 100644 --- a/mmv1/products/compute/BackendServiceSignedUrlKey.yaml +++ b/mmv1/products/compute/BackendServiceSignedUrlKey.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/Disk.yaml b/mmv1/products/compute/Disk.yaml index 1e2e8ba7b787..3472e11af504 100644 --- a/mmv1/products/compute/Disk.yaml +++ b/mmv1/products/compute/Disk.yaml @@ -47,15 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: parent_resource_attribute: 'name' @@ -72,7 +65,7 @@ custom_code: pre_delete: 'templates/terraform/pre_delete/detach_disk.tmpl' custom_diff: - 'customdiff.ForceNewIfChange("size", IsDiskShrinkage)' - - 'hyperDiskIopsUpdateDiffSupress' + - 'hyperDiskIopsUpdateDiffSuppress' examples: - name: 'disk_basic' primary_resource_id: 'default' @@ -100,6 +93,23 @@ parameters: custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' resource: 'Zone' imports: 'name' + - name: 'snapshot' + type: ResourceRef + description: | + The source snapshot used to create this disk. You can provide this as + a partial or full URL to the resource. If the snapshot is in another + project than this disk, you must supply a full URL. For example, the + following are valid values: + + * `https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot` + * `projects/project/global/snapshots/snapshot` + * `global/snapshots/snapshot` + * `snapshot` + api_name: sourceSnapshot + custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' + resource: 'Snapshot' + imports: 'selfLink' +properties: - name: 'sourceImageEncryptionKey' type: NestedObject description: | @@ -194,22 +204,6 @@ parameters: description: | The service account used for the encryption request for the given KMS key. If absent, the Compute Engine Service Agent service account is used. - - name: 'snapshot' - type: ResourceRef - description: | - The source snapshot used to create this disk. You can provide this as - a partial or full URL to the resource. If the snapshot is in another - project than this disk, you must supply a full URL. For example, the - following are valid values: - - * `https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot` - * `projects/project/global/snapshots/snapshot` - * `global/snapshots/snapshot` - * `snapshot` - api_name: sourceSnapshot - custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' - resource: 'Snapshot' - imports: 'selfLink' - name: 'sourceSnapshotEncryptionKey' type: NestedObject description: | @@ -255,7 +249,7 @@ parameters: snapshot ID would identify the exact version of the snapshot that was used. output: true -properties: + - name: 'labelFingerprint' type: Fingerprint description: | @@ -365,7 +359,7 @@ properties: * projects/{project}/regions/{region}/disks/{disk} * zones/{zone}/disks/{disk} * regions/{region}/disks/{disk} - diff_suppress_func: 'sourceDiskDiffSupress' + diff_suppress_func: 'sourceDiskDiffSuppress' - name: 'sourceDiskId' type: String description: | @@ -496,14 +490,17 @@ properties: - name: 'storagePool' type: String description: | - The URL of the storage pool in which the new disk is created. + The URL or the name of the storage pool in which the new disk is created. For example: * https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/storagePools/{storagePool} * /projects/{project}/zones/{zone}/storagePools/{storagePool} + * /zones/{zone}/storagePools/{storagePool} + * /{storagePool} required: false immutable: true diff_suppress_func: 'tpgresource.CompareResourceNames' custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' + custom_expand: 'templates/terraform/custom_expand/storage_pool_full_url.tmpl' - name: 'accessMode' type: String description: | diff --git a/mmv1/products/compute/DiskResourcePolicyAttachment.yaml b/mmv1/products/compute/DiskResourcePolicyAttachment.yaml index b301a4debb44..eba8c82256b6 100644 --- a/mmv1/products/compute/DiskResourcePolicyAttachment.yaml +++ b/mmv1/products/compute/DiskResourcePolicyAttachment.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/ExternalVpnGateway.yaml b/mmv1/products/compute/ExternalVpnGateway.yaml index a49f8bacc306..373bc1d5e912 100644 --- a/mmv1/products/compute/ExternalVpnGateway.yaml +++ b/mmv1/products/compute/ExternalVpnGateway.yaml @@ -32,15 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/Firewall.yaml b/mmv1/products/compute/Firewall.yaml index c048c0a918e2..0fe92be2c8d0 100644 --- a/mmv1/products/compute/Firewall.yaml +++ b/mmv1/products/compute/Firewall.yaml @@ -47,15 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/firewall.tmpl' diff --git a/mmv1/products/compute/FirewallPolicyRule.yaml b/mmv1/products/compute/FirewallPolicyRule.yaml index 1264e8cd3345..0fa55ce95f89 100644 --- a/mmv1/products/compute/FirewallPolicyRule.yaml +++ b/mmv1/products/compute/FirewallPolicyRule.yaml @@ -13,6 +13,7 @@ --- name: 'FirewallPolicyRule' +api_resource_type_kind: FirewallPolicy kind: 'compute#firewallPolicyRule' description: | Represents a rule that describes one or more match conditions along with the action to be taken when traffic matches this condition (allow or deny). diff --git a/mmv1/products/compute/ForwardingRule.yaml b/mmv1/products/compute/ForwardingRule.yaml index 5dfc75b43ed6..ec3add76aa4a 100644 --- a/mmv1/products/compute/ForwardingRule.yaml +++ b/mmv1/products/compute/ForwardingRule.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/compute_forwarding_rule.go.tmpl' diff --git a/mmv1/products/compute/GlobalAddress.yaml b/mmv1/products/compute/GlobalAddress.yaml index 89679209a73c..b30944f2f053 100644 --- a/mmv1/products/compute/GlobalAddress.yaml +++ b/mmv1/products/compute/GlobalAddress.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: pre_create: 'templates/terraform/pre_create/compute_global_address.go.tmpl' diff --git a/mmv1/products/compute/GlobalForwardingRule.yaml b/mmv1/products/compute/GlobalForwardingRule.yaml index 8cc0bffb71c3..6f791325c80d 100644 --- a/mmv1/products/compute/GlobalForwardingRule.yaml +++ b/mmv1/products/compute/GlobalForwardingRule.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: post_create: 'templates/terraform/post_create/labels.tmpl' @@ -485,6 +478,25 @@ properties: update_url: 'projects/{{project}}/global/forwardingRules/{{name}}/setTarget' update_verb: 'POST' diff_suppress_func: 'tpgresource.CompareSelfLinkRelativePaths' + - name: 'networkTier' + type: Enum + description: | + This signifies the networking tier used for configuring + this load balancer and can only take the following values: + `PREMIUM`, `STANDARD`. + + For regional ForwardingRule, the valid values are `PREMIUM` and + `STANDARD`. For GlobalForwardingRule, the valid value is + `PREMIUM`. + + If this field is not specified, it is assumed to be `PREMIUM`. + If `IPAddress` is specified, this value must be equal to the + networkTier of the Address. + immutable: true + default_from_api: true + enum_values: + - 'PREMIUM' + - 'STANDARD' - name: 'serviceDirectoryRegistrations' type: Array description: | diff --git a/mmv1/products/compute/GlobalNetworkEndpoint.yaml b/mmv1/products/compute/GlobalNetworkEndpoint.yaml index 4439f55b071f..740696cb9e60 100644 --- a/mmv1/products/compute/GlobalNetworkEndpoint.yaml +++ b/mmv1/products/compute/GlobalNetworkEndpoint.yaml @@ -42,15 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - ipAddress - fqdn diff --git a/mmv1/products/compute/GlobalNetworkEndpointGroup.yaml b/mmv1/products/compute/GlobalNetworkEndpointGroup.yaml index ea990438f560..fffee1e5fe68 100644 --- a/mmv1/products/compute/GlobalNetworkEndpointGroup.yaml +++ b/mmv1/products/compute/GlobalNetworkEndpointGroup.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/HaVpnGateway.yaml b/mmv1/products/compute/HaVpnGateway.yaml index 2526a4ab6478..34e01079df17 100644 --- a/mmv1/products/compute/HaVpnGateway.yaml +++ b/mmv1/products/compute/HaVpnGateway.yaml @@ -37,17 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: +schema_version: 1 +state_upgraders: true examples: - name: 'ha_vpn_gateway_basic' primary_resource_id: 'ha_gateway1' diff --git a/mmv1/products/compute/HealthCheck.yaml b/mmv1/products/compute/HealthCheck.yaml index 7b5c40e635b3..26faf49ee113 100644 --- a/mmv1/products/compute/HealthCheck.yaml +++ b/mmv1/products/compute/HealthCheck.yaml @@ -46,15 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/health_check.tmpl' diff --git a/mmv1/products/compute/HttpHealthCheck.yaml b/mmv1/products/compute/HttpHealthCheck.yaml index 7621f6547b61..ef51492cefdf 100644 --- a/mmv1/products/compute/HttpHealthCheck.yaml +++ b/mmv1/products/compute/HttpHealthCheck.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/HttpsHealthCheck.yaml b/mmv1/products/compute/HttpsHealthCheck.yaml index 7b43e3ea112c..48c4cb690f38 100644 --- a/mmv1/products/compute/HttpsHealthCheck.yaml +++ b/mmv1/products/compute/HttpsHealthCheck.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/Image.yaml b/mmv1/products/compute/Image.yaml index b78abce38088..733f0e7fa889 100644 --- a/mmv1/products/compute/Image.yaml +++ b/mmv1/products/compute/Image.yaml @@ -48,15 +48,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.imageUser' diff --git a/mmv1/products/compute/Instance.yaml b/mmv1/products/compute/Instance.yaml index 4963847e1c07..fc8fd5e82cf6 100644 --- a/mmv1/products/compute/Instance.yaml +++ b/mmv1/products/compute/Instance.yaml @@ -30,15 +30,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.osLogin' diff --git a/mmv1/products/compute/InstanceGroup.yaml b/mmv1/products/compute/InstanceGroup.yaml index 67c902e29936..c7cce2a98124 100644 --- a/mmv1/products/compute/InstanceGroup.yaml +++ b/mmv1/products/compute/InstanceGroup.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: parameters: diff --git a/mmv1/products/compute/InstanceGroupManager.yaml b/mmv1/products/compute/InstanceGroupManager.yaml index 814d41abd0e4..fe416170ccec 100644 --- a/mmv1/products/compute/InstanceGroupManager.yaml +++ b/mmv1/products/compute/InstanceGroupManager.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: parameters: diff --git a/mmv1/products/compute/InstanceGroupMembership.yaml b/mmv1/products/compute/InstanceGroupMembership.yaml index 9b8ad1f91220..2e3120a32700 100644 --- a/mmv1/products/compute/InstanceGroupMembership.yaml +++ b/mmv1/products/compute/InstanceGroupMembership.yaml @@ -51,15 +51,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - instance nested_query: diff --git a/mmv1/products/compute/InstanceGroupNamedPort.yaml b/mmv1/products/compute/InstanceGroupNamedPort.yaml index 83cfb674421e..4b8c4d9f5c7a 100644 --- a/mmv1/products/compute/InstanceGroupNamedPort.yaml +++ b/mmv1/products/compute/InstanceGroupNamedPort.yaml @@ -43,15 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - port - name diff --git a/mmv1/products/compute/InstanceSettings.yaml b/mmv1/products/compute/InstanceSettings.yaml index b702e25879ed..1ce2c6746646 100644 --- a/mmv1/products/compute/InstanceSettings.yaml +++ b/mmv1/products/compute/InstanceSettings.yaml @@ -38,15 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: custom_delete: 'templates/terraform/custom_delete/clear_instance_settings.go.tmpl' test_check_destroy: 'templates/terraform/custom_check_destroy/skip_delete_during_test.go.tmpl' diff --git a/mmv1/products/compute/Interconnect.yaml b/mmv1/products/compute/Interconnect.yaml index 308ec75e4fc3..afc17655ddf0 100644 --- a/mmv1/products/compute/Interconnect.yaml +++ b/mmv1/products/compute/Interconnect.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 10000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: constants: 'templates/terraform/constants/interconnect.go.tmpl' post_create: 'templates/terraform/post_create/labels.tmpl' diff --git a/mmv1/products/compute/InterconnectAttachment.yaml b/mmv1/products/compute/InterconnectAttachment.yaml index 2dc641ba7ced..a31185bfe08b 100644 --- a/mmv1/products/compute/InterconnectAttachment.yaml +++ b/mmv1/products/compute/InterconnectAttachment.yaml @@ -30,15 +30,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/interconnect_attachment.go.tmpl' diff --git a/mmv1/products/compute/MachineImage.yaml b/mmv1/products/compute/MachineImage.yaml index 1e5ff5de1b54..dab56f9c8e34 100644 --- a/mmv1/products/compute/MachineImage.yaml +++ b/mmv1/products/compute/MachineImage.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.admin' diff --git a/mmv1/products/compute/ManagedSslCertificate.yaml b/mmv1/products/compute/ManagedSslCertificate.yaml index 3e3c222fb0ec..0bbb6688bf25 100644 --- a/mmv1/products/compute/ManagedSslCertificate.yaml +++ b/mmv1/products/compute/ManagedSslCertificate.yaml @@ -54,9 +54,6 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 @@ -64,11 +61,7 @@ async: # on the provisioning process either succeeding or failing completely. delete_minutes: 30 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/compute_managed_ssl_certificate.go.tmpl' diff --git a/mmv1/products/compute/Network.yaml b/mmv1/products/compute/Network.yaml index 4a722c4b3193..d67d4c02fdb9 100644 --- a/mmv1/products/compute/Network.yaml +++ b/mmv1/products/compute/Network.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: encoder: 'templates/terraform/encoders/compute_network.go.tmpl' diff --git a/mmv1/products/compute/NetworkAttachment.yaml b/mmv1/products/compute/NetworkAttachment.yaml index 6e1859398910..a4d6f97ca575 100644 --- a/mmv1/products/compute/NetworkAttachment.yaml +++ b/mmv1/products/compute/NetworkAttachment.yaml @@ -32,15 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/NetworkEdgeSecurityService.yaml b/mmv1/products/compute/NetworkEdgeSecurityService.yaml index 14594bcb1ef7..acff3486a9f6 100644 --- a/mmv1/products/compute/NetworkEdgeSecurityService.yaml +++ b/mmv1/products/compute/NetworkEdgeSecurityService.yaml @@ -38,15 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: # Skipping the sweeper since we need to sweep multiple regions exclude_sweeper: true diff --git a/mmv1/products/compute/NetworkEndpoint.yaml b/mmv1/products/compute/NetworkEndpoint.yaml index 69a43ca3b49d..67b16dc943d7 100644 --- a/mmv1/products/compute/NetworkEndpoint.yaml +++ b/mmv1/products/compute/NetworkEndpoint.yaml @@ -48,15 +48,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - instance - ipAddress diff --git a/mmv1/products/compute/NetworkEndpointGroup.yaml b/mmv1/products/compute/NetworkEndpointGroup.yaml index 90adf726d926..0eabc08b86b1 100644 --- a/mmv1/products/compute/NetworkEndpointGroup.yaml +++ b/mmv1/products/compute/NetworkEndpointGroup.yaml @@ -46,15 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/compute_network_endpoint_group.go.tmpl' diff --git a/mmv1/products/compute/NetworkEndpoints.yaml b/mmv1/products/compute/NetworkEndpoints.yaml index e1f8d296721d..872e9352911b 100644 --- a/mmv1/products/compute/NetworkEndpoints.yaml +++ b/mmv1/products/compute/NetworkEndpoints.yaml @@ -54,15 +54,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - networkEndpointGroup custom_code: diff --git a/mmv1/products/compute/NetworkFirewallPolicy.yaml b/mmv1/products/compute/NetworkFirewallPolicy.yaml index 5aaa01d52946..e003f212f534 100644 --- a/mmv1/products/compute/NetworkFirewallPolicy.yaml +++ b/mmv1/products/compute/NetworkFirewallPolicy.yaml @@ -29,15 +29,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: legacy_long_form_project: true examples: diff --git a/mmv1/products/compute/NetworkFirewallPolicyAssociation.yaml b/mmv1/products/compute/NetworkFirewallPolicyAssociation.yaml index c24049cdcc80..dc8b27530382 100644 --- a/mmv1/products/compute/NetworkFirewallPolicyAssociation.yaml +++ b/mmv1/products/compute/NetworkFirewallPolicyAssociation.yaml @@ -13,6 +13,7 @@ --- name: 'NetworkFirewallPolicyAssociation' +api_resource_type_kind: FirewallPolicy kind: 'compute#firewallPolicyAssociation' description: | The Compute NetworkFirewallPolicyAssociation resource @@ -40,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' examples: - name: 'network_firewall_policy_association' primary_resource_id: 'default' diff --git a/mmv1/products/compute/NetworkFirewallPolicyRule.yaml b/mmv1/products/compute/NetworkFirewallPolicyRule.yaml index 93b97ebb0cc1..9623c6bf980c 100644 --- a/mmv1/products/compute/NetworkFirewallPolicyRule.yaml +++ b/mmv1/products/compute/NetworkFirewallPolicyRule.yaml @@ -43,15 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' examples: - name: 'network_firewall_policy_rule' primary_resource_id: 'primary' diff --git a/mmv1/products/compute/NetworkFirewallPolicyWithRules.yaml b/mmv1/products/compute/NetworkFirewallPolicyWithRules.yaml index a73e10365949..fd53efd404f6 100644 --- a/mmv1/products/compute/NetworkFirewallPolicyWithRules.yaml +++ b/mmv1/products/compute/NetworkFirewallPolicyWithRules.yaml @@ -30,15 +30,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: constants: 'templates/terraform/constants/resource_compute_network_firewall_policy_with_rules.go.tmpl' encoder: 'templates/terraform/encoders/resource_compute_network_firewall_policy_with_rules.go.tmpl' diff --git a/mmv1/products/compute/NetworkPeeringRoutesConfig.yaml b/mmv1/products/compute/NetworkPeeringRoutesConfig.yaml index e3247eda280e..2ff48235d2fd 100644 --- a/mmv1/products/compute/NetworkPeeringRoutesConfig.yaml +++ b/mmv1/products/compute/NetworkPeeringRoutesConfig.yaml @@ -44,15 +44,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - peering nested_query: diff --git a/mmv1/products/compute/NodeGroup.yaml b/mmv1/products/compute/NodeGroup.yaml index e011a8300469..46a52682e294 100644 --- a/mmv1/products/compute/NodeGroup.yaml +++ b/mmv1/products/compute/NodeGroup.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: pre_create: 'templates/terraform/pre_create/compute_node_group_url_replace.go.tmpl' diff --git a/mmv1/products/compute/NodeTemplate.yaml b/mmv1/products/compute/NodeTemplate.yaml index 8b77c1109196..e23d4317d85d 100644 --- a/mmv1/products/compute/NodeTemplate.yaml +++ b/mmv1/products/compute/NodeTemplate.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/PacketMirroring.yaml b/mmv1/products/compute/PacketMirroring.yaml index d73b3f1de04a..123fcc99c203 100644 --- a/mmv1/products/compute/PacketMirroring.yaml +++ b/mmv1/products/compute/PacketMirroring.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'compute_packet_mirroring_full' diff --git a/mmv1/products/compute/PerInstanceConfig.yaml b/mmv1/products/compute/PerInstanceConfig.yaml index 4d577afe3ffc..f14ab742b838 100644 --- a/mmv1/products/compute/PerInstanceConfig.yaml +++ b/mmv1/products/compute/PerInstanceConfig.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/ProjectCloudArmorTier.yaml b/mmv1/products/compute/ProjectCloudArmorTier.yaml index 5c8ebe33fd73..e3d612edea31 100644 --- a/mmv1/products/compute/ProjectCloudArmorTier.yaml +++ b/mmv1/products/compute/ProjectCloudArmorTier.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: custom_delete: 'templates/terraform/custom_delete/only_remove_from_state.go.tmpl' examples: @@ -72,3 +65,4 @@ properties: enum_values: - 'CA_STANDARD' - 'CA_ENTERPRISE_PAYGO' + - 'CA_ENTERPRISE_ANNUAL' diff --git a/mmv1/products/compute/PublicAdvertisedPrefix.yaml b/mmv1/products/compute/PublicAdvertisedPrefix.yaml index a040591657a0..e21d5e9dd786 100644 --- a/mmv1/products/compute/PublicAdvertisedPrefix.yaml +++ b/mmv1/products/compute/PublicAdvertisedPrefix.yaml @@ -32,15 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'public_advertised_prefixes_basic' diff --git a/mmv1/products/compute/PublicDelegatedPrefix.yaml b/mmv1/products/compute/PublicDelegatedPrefix.yaml index da8ed28cdefc..966f528f0cb6 100644 --- a/mmv1/products/compute/PublicDelegatedPrefix.yaml +++ b/mmv1/products/compute/PublicDelegatedPrefix.yaml @@ -32,15 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'public_delegated_prefixes_basic' diff --git a/mmv1/products/compute/RegionAutoscaler.yaml b/mmv1/products/compute/RegionAutoscaler.yaml index 064189025d4f..af0a7b0838ce 100644 --- a/mmv1/products/compute/RegionAutoscaler.yaml +++ b/mmv1/products/compute/RegionAutoscaler.yaml @@ -38,15 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/RegionBackendService.yaml b/mmv1/products/compute/RegionBackendService.yaml index ce3cc796194f..cfb7ba08c9d8 100644 --- a/mmv1/products/compute/RegionBackendService.yaml +++ b/mmv1/products/compute/RegionBackendService.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.admin' diff --git a/mmv1/products/compute/RegionCommitment.yaml b/mmv1/products/compute/RegionCommitment.yaml index 177ac627c8a4..d9254e00a3ea 100644 --- a/mmv1/products/compute/RegionCommitment.yaml +++ b/mmv1/products/compute/RegionCommitment.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/RegionDisk.yaml b/mmv1/products/compute/RegionDisk.yaml index 56cadab731ae..6ca8d52ee24d 100644 --- a/mmv1/products/compute/RegionDisk.yaml +++ b/mmv1/products/compute/RegionDisk.yaml @@ -47,15 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: parent_resource_attribute: 'name' @@ -70,7 +63,7 @@ custom_code: pre_delete: 'templates/terraform/pre_delete/detach_disk.tmpl' custom_diff: - 'customdiff.ForceNewIfChange("size", IsDiskShrinkage)' - - 'hyperDiskIopsUpdateDiffSupress' + - 'hyperDiskIopsUpdateDiffSuppress' examples: - name: 'region_disk_basic' primary_resource_id: 'regiondisk' @@ -100,6 +93,22 @@ parameters: custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' resource: 'Region' imports: 'name' + - name: 'snapshot' + type: ResourceRef + description: | + The source snapshot used to create this disk. You can provide this as + a partial or full URL to the resource. For example, the following are + valid values: + + * `https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot` + * `projects/project/global/snapshots/snapshot` + * `global/snapshots/snapshot` + * `snapshot` + api_name: sourceSnapshot + custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' + resource: 'Snapshot' + imports: 'selfLink' +properties: - name: 'diskEncryptionKey' type: NestedObject description: | @@ -134,21 +143,6 @@ parameters: type: String description: | The name of the encryption key that is stored in Google Cloud KMS. - - name: 'snapshot' - type: ResourceRef - description: | - The source snapshot used to create this disk. You can provide this as - a partial or full URL to the resource. For example, the following are - valid values: - - * `https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot` - * `projects/project/global/snapshots/snapshot` - * `global/snapshots/snapshot` - * `snapshot` - api_name: sourceSnapshot - custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' - resource: 'Snapshot' - imports: 'selfLink' - name: 'sourceSnapshotEncryptionKey' type: NestedObject description: | @@ -184,7 +178,6 @@ parameters: snapshot ID would identify the exact version of the snapshot that was used. output: true -properties: - name: 'labelFingerprint' type: Fingerprint description: | @@ -313,7 +306,7 @@ properties: * projects/{project}/regions/{region}/disks/{disk} * zones/{zone}/disks/{disk} * regions/{region}/disks/{disk} - diff_suppress_func: 'sourceDiskDiffSupress' + diff_suppress_func: 'sourceDiskDiffSuppress' - name: 'sourceDiskId' type: String description: | diff --git a/mmv1/products/compute/RegionDiskResourcePolicyAttachment.yaml b/mmv1/products/compute/RegionDiskResourcePolicyAttachment.yaml index 2aba34f08240..5ae9a56bc2a9 100644 --- a/mmv1/products/compute/RegionDiskResourcePolicyAttachment.yaml +++ b/mmv1/products/compute/RegionDiskResourcePolicyAttachment.yaml @@ -13,7 +13,7 @@ --- name: 'RegionDiskResourcePolicyAttachment' -api_resource_type_kind: Disk +api_resource_type_kind: RegionDisk description: | Adds existing resource policies to a disk. You can only add one policy which will be applied to this disk for scheduling snapshot creation. @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/RegionHealthCheck.yaml b/mmv1/products/compute/RegionHealthCheck.yaml index 88adaa7ec03f..ee4539a3f069 100644 --- a/mmv1/products/compute/RegionHealthCheck.yaml +++ b/mmv1/products/compute/RegionHealthCheck.yaml @@ -43,15 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: encoder: 'templates/terraform/encoders/health_check_type.tmpl' diff --git a/mmv1/products/compute/RegionInstanceGroupManager.yaml b/mmv1/products/compute/RegionInstanceGroupManager.yaml index ac4a36de2c9d..6b5e4c1058e3 100644 --- a/mmv1/products/compute/RegionInstanceGroupManager.yaml +++ b/mmv1/products/compute/RegionInstanceGroupManager.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: parameters: diff --git a/mmv1/products/compute/RegionNetworkEndpoint.yaml b/mmv1/products/compute/RegionNetworkEndpoint.yaml index 94feb20a0368..090b95ebcb53 100644 --- a/mmv1/products/compute/RegionNetworkEndpoint.yaml +++ b/mmv1/products/compute/RegionNetworkEndpoint.yaml @@ -44,15 +44,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - ipAddress - fqdn diff --git a/mmv1/products/compute/RegionNetworkEndpointGroup.yaml b/mmv1/products/compute/RegionNetworkEndpointGroup.yaml index ef911ae8f502..e7d36c985ff9 100644 --- a/mmv1/products/compute/RegionNetworkEndpointGroup.yaml +++ b/mmv1/products/compute/RegionNetworkEndpointGroup.yaml @@ -40,15 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: @@ -170,6 +163,20 @@ properties: custom_expand: 'templates/terraform/custom_expand/resourceref_with_validation.go.tmpl' resource: 'Subnetwork' imports: 'selfLink' + - name: 'pscData' + type: NestedObject + description: | + This field is only used for PSC NEGs. + + properties: + - name: 'producerPort' + type: String + ignore_read: true + description: | + The PSC producer port to use when consumer PSC NEG connects to a producer. If + this flag isn't specified for a PSC NEG with endpoint type + private-service-connect, then PSC NEG will be connected to a first port in the + available PSC producer port range. - name: 'cloudRun' type: NestedObject description: | diff --git a/mmv1/products/compute/RegionNetworkFirewallPolicy.yaml b/mmv1/products/compute/RegionNetworkFirewallPolicy.yaml index 51dbe294156f..92531c95af69 100644 --- a/mmv1/products/compute/RegionNetworkFirewallPolicy.yaml +++ b/mmv1/products/compute/RegionNetworkFirewallPolicy.yaml @@ -29,15 +29,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: legacy_long_form_project: true examples: diff --git a/mmv1/products/compute/RegionNetworkFirewallPolicyAssociation.yaml b/mmv1/products/compute/RegionNetworkFirewallPolicyAssociation.yaml index a30ff8a73493..7810c00254bc 100644 --- a/mmv1/products/compute/RegionNetworkFirewallPolicyAssociation.yaml +++ b/mmv1/products/compute/RegionNetworkFirewallPolicyAssociation.yaml @@ -13,6 +13,7 @@ --- name: 'RegionNetworkFirewallPolicyAssociation' +api_resource_type_kind: FirewallPolicy kind: 'compute#firewallPolicyAssociation' description: | The Compute NetworkFirewallPolicyAssociation resource @@ -40,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' examples: - name: 'region_network_firewall_policy_association' primary_resource_id: 'default' diff --git a/mmv1/products/compute/RegionNetworkFirewallPolicyRule.yaml b/mmv1/products/compute/RegionNetworkFirewallPolicyRule.yaml index d62b527a63d4..f093312f413e 100644 --- a/mmv1/products/compute/RegionNetworkFirewallPolicyRule.yaml +++ b/mmv1/products/compute/RegionNetworkFirewallPolicyRule.yaml @@ -44,15 +44,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_diff: - 'tpgresource.DefaultProviderRegion' examples: diff --git a/mmv1/products/compute/RegionNetworkFirewallPolicyWithRules.yaml b/mmv1/products/compute/RegionNetworkFirewallPolicyWithRules.yaml index 7277398ab659..e5c5957e0f4f 100644 --- a/mmv1/products/compute/RegionNetworkFirewallPolicyWithRules.yaml +++ b/mmv1/products/compute/RegionNetworkFirewallPolicyWithRules.yaml @@ -30,15 +30,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: constants: 'templates/terraform/constants/resource_compute_region_network_firewall_policy_with_rules.go.tmpl' encoder: 'templates/terraform/encoders/resource_compute_region_network_firewall_policy_with_rules.go.tmpl' diff --git a/mmv1/products/compute/RegionPerInstanceConfig.yaml b/mmv1/products/compute/RegionPerInstanceConfig.yaml index 67089ff07079..ab079b507d70 100644 --- a/mmv1/products/compute/RegionPerInstanceConfig.yaml +++ b/mmv1/products/compute/RegionPerInstanceConfig.yaml @@ -42,15 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/compute/RegionSecurityPolicy.yaml b/mmv1/products/compute/RegionSecurityPolicy.yaml index f920ab8c5511..f5dad0221dba 100644 --- a/mmv1/products/compute/RegionSecurityPolicy.yaml +++ b/mmv1/products/compute/RegionSecurityPolicy.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'region_security_policy_basic' diff --git a/mmv1/products/compute/RegionSecurityPolicyRule.yaml b/mmv1/products/compute/RegionSecurityPolicyRule.yaml index ded0cf754597..3bdd2eb7aac2 100644 --- a/mmv1/products/compute/RegionSecurityPolicyRule.yaml +++ b/mmv1/products/compute/RegionSecurityPolicyRule.yaml @@ -42,15 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/region_security_policy_default_rule_update_on_create.go.tmpl' pre_delete: 'templates/terraform/pre_delete/security_policy_default_rule_delete.go.tmpl' diff --git a/mmv1/products/compute/RegionSslCertificate.yaml b/mmv1/products/compute/RegionSslCertificate.yaml index e5b796d9d04a..629082845043 100644 --- a/mmv1/products/compute/RegionSslCertificate.yaml +++ b/mmv1/products/compute/RegionSslCertificate.yaml @@ -45,15 +45,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/ssl_certificate.tmpl' diff --git a/mmv1/products/compute/RegionSslPolicy.yaml b/mmv1/products/compute/RegionSslPolicy.yaml index ea216cd7ce9a..ea14fe84fe77 100644 --- a/mmv1/products/compute/RegionSslPolicy.yaml +++ b/mmv1/products/compute/RegionSslPolicy.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/region_ssl_policy.tmpl' diff --git a/mmv1/products/compute/RegionTargetHttpProxy.yaml b/mmv1/products/compute/RegionTargetHttpProxy.yaml index 5d7168ba5338..54164f8d6e4b 100644 --- a/mmv1/products/compute/RegionTargetHttpProxy.yaml +++ b/mmv1/products/compute/RegionTargetHttpProxy.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'region_target_http_proxy_basic' diff --git a/mmv1/products/compute/RegionTargetHttpsProxy.yaml b/mmv1/products/compute/RegionTargetHttpsProxy.yaml index 68405584ee97..6c8325ddfc86 100644 --- a/mmv1/products/compute/RegionTargetHttpsProxy.yaml +++ b/mmv1/products/compute/RegionTargetHttpsProxy.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/compute_region_target_https_proxy.go.tmpl' # update_encoder is usually the same as encoder by default. This resource is an uncommon case where the whole resource diff --git a/mmv1/products/compute/RegionTargetTcpProxy.yaml b/mmv1/products/compute/RegionTargetTcpProxy.yaml index 2d7a9473a218..46917a6079f8 100644 --- a/mmv1/products/compute/RegionTargetTcpProxy.yaml +++ b/mmv1/products/compute/RegionTargetTcpProxy.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'region_target_tcp_proxy_basic' diff --git a/mmv1/products/compute/RegionUrlMap.yaml b/mmv1/products/compute/RegionUrlMap.yaml index ecd19552159a..1d8c982b4a28 100644 --- a/mmv1/products/compute/RegionUrlMap.yaml +++ b/mmv1/products/compute/RegionUrlMap.yaml @@ -30,15 +30,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/Reservation.yaml b/mmv1/products/compute/Reservation.yaml index 7db5bfc96cad..4c2e3cc13b83 100644 --- a/mmv1/products/compute/Reservation.yaml +++ b/mmv1/products/compute/Reservation.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: update_encoder: 'templates/terraform/update_encoder/reservation.go.tmpl' diff --git a/mmv1/products/compute/ResizeRequest.yaml b/mmv1/products/compute/ResizeRequest.yaml index 4540cf55dbc3..cd2faac099d0 100644 --- a/mmv1/products/compute/ResizeRequest.yaml +++ b/mmv1/products/compute/ResizeRequest.yaml @@ -48,15 +48,8 @@ async: # actions: ['create', 'update', 'delete'] operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' ### Update method ### # Resize requests are currently not update-able diff --git a/mmv1/products/compute/ResourcePolicy.yaml b/mmv1/products/compute/ResourcePolicy.yaml index de3eaecdce61..b71acc2def9c 100644 --- a/mmv1/products/compute/ResourcePolicy.yaml +++ b/mmv1/products/compute/ResourcePolicy.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/compute_resource_policy.go.tmpl' @@ -258,7 +251,7 @@ properties: type: Boolean description: | Whether to perform a 'guest aware' snapshot. - send_empty_value: true + send_empty_value: false at_least_one_of: - 'snapshot_schedule_policy.0.snapshot_properties.0.labels' - 'snapshot_schedule_policy.0.snapshot_properties.0.storage_locations' diff --git a/mmv1/products/compute/Route.yaml b/mmv1/products/compute/Route.yaml index 0c53770cd87c..ebdd902e21e6 100644 --- a/mmv1/products/compute/Route.yaml +++ b/mmv1/products/compute/Route.yaml @@ -61,15 +61,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/route.tmpl' diff --git a/mmv1/products/compute/Router.yaml b/mmv1/products/compute/Router.yaml index b152c433bd8a..1b231c1019d6 100644 --- a/mmv1/products/compute/Router.yaml +++ b/mmv1/products/compute/Router.yaml @@ -37,15 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/router.go.tmpl' diff --git a/mmv1/products/compute/RouterNat.yaml b/mmv1/products/compute/RouterNat.yaml index 426194faeef2..dc7fd525db8a 100644 --- a/mmv1/products/compute/RouterNat.yaml +++ b/mmv1/products/compute/RouterNat.yaml @@ -43,15 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'nats' identity: - name diff --git a/mmv1/products/compute/RouterNatAddress.yaml b/mmv1/products/compute/RouterNatAddress.yaml index c1347ec622d8..d203f5e5dcd6 100644 --- a/mmv1/products/compute/RouterNatAddress.yaml +++ b/mmv1/products/compute/RouterNatAddress.yaml @@ -44,15 +44,8 @@ async: type: 'OpAsync' operation: base_url: 'projects/{{project}}/regions/{{regions}}/operations/{{op_id}}' - kind: 'compute#operation' - path: 'routerNat' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'nats' identity: - routerNat diff --git a/mmv1/products/compute/RouterRoutePolicy.yaml b/mmv1/products/compute/RouterRoutePolicy.yaml index b0b98bb74152..56f990cbb1c8 100644 --- a/mmv1/products/compute/RouterRoutePolicy.yaml +++ b/mmv1/products/compute/RouterRoutePolicy.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: decoder: 'templates/terraform/decoders/unwrap_route_policy_resource.go.tmpl' examples: diff --git a/mmv1/products/compute/SecurityPolicyRule.yaml b/mmv1/products/compute/SecurityPolicyRule.yaml index 53a0e5830498..07d958ec6aee 100644 --- a/mmv1/products/compute/SecurityPolicyRule.yaml +++ b/mmv1/products/compute/SecurityPolicyRule.yaml @@ -41,15 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/security_policy_default_rule_update_on_create.go.tmpl' pre_delete: 'templates/terraform/pre_delete/security_policy_default_rule_delete.go.tmpl' diff --git a/mmv1/products/compute/ServiceAttachment.yaml b/mmv1/products/compute/ServiceAttachment.yaml index 5a40d5130f19..3e4254b37208 100644 --- a/mmv1/products/compute/ServiceAttachment.yaml +++ b/mmv1/products/compute/ServiceAttachment.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: constants: 'templates/terraform/constants/compute_service_attachment.go.tmpl' update_encoder: 'templates/terraform/update_encoder/compute_service_attachment.go.tmpl' diff --git a/mmv1/products/compute/Snapshot.yaml b/mmv1/products/compute/Snapshot.yaml index f3db7a1ee1e4..a6447df32eee 100644 --- a/mmv1/products/compute/Snapshot.yaml +++ b/mmv1/products/compute/Snapshot.yaml @@ -48,15 +48,8 @@ async: type: 'OpAsync' operation: full_url: 'selfLink' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: parent_resource_attribute: 'name' diff --git a/mmv1/products/compute/SslCertificate.yaml b/mmv1/products/compute/SslCertificate.yaml index a4e3e2a762cd..9a9a30bfb35f 100644 --- a/mmv1/products/compute/SslCertificate.yaml +++ b/mmv1/products/compute/SslCertificate.yaml @@ -44,15 +44,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/ssl_certificate.tmpl' diff --git a/mmv1/products/compute/SslPolicy.yaml b/mmv1/products/compute/SslPolicy.yaml index c78369eee147..08e288fc82f0 100644 --- a/mmv1/products/compute/SslPolicy.yaml +++ b/mmv1/products/compute/SslPolicy.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/ssl_policy.tmpl' diff --git a/mmv1/products/compute/Subnetwork.yaml b/mmv1/products/compute/Subnetwork.yaml index cb97cf761167..193862d5ba51 100644 --- a/mmv1/products/compute/Subnetwork.yaml +++ b/mmv1/products/compute/Subnetwork.yaml @@ -55,15 +55,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' iam_policy: allowed_iam_role: 'roles/compute.networkUser' @@ -410,7 +403,6 @@ properties: enum_values: - 'IPV4_ONLY' - 'IPV4_IPV6' - - 'IPV6_ONLY' - name: 'ipv6AccessType' type: Enum description: | diff --git a/mmv1/products/compute/TargetGrpcProxy.yaml b/mmv1/products/compute/TargetGrpcProxy.yaml index a8ea91e0905e..b3ad09fa674f 100644 --- a/mmv1/products/compute/TargetGrpcProxy.yaml +++ b/mmv1/products/compute/TargetGrpcProxy.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/TargetHttpProxy.yaml b/mmv1/products/compute/TargetHttpProxy.yaml index b8f8d271d0e0..cd1ff2f7d3dc 100644 --- a/mmv1/products/compute/TargetHttpProxy.yaml +++ b/mmv1/products/compute/TargetHttpProxy.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/TargetHttpsProxy.yaml b/mmv1/products/compute/TargetHttpsProxy.yaml index e8de3f3bc99b..c9230bae09bd 100644 --- a/mmv1/products/compute/TargetHttpsProxy.yaml +++ b/mmv1/products/compute/TargetHttpsProxy.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: encoder: 'templates/terraform/encoders/compute_target_https_proxy.go.tmpl' diff --git a/mmv1/products/compute/TargetInstance.yaml b/mmv1/products/compute/TargetInstance.yaml index 24462fdea0f8..a0370e569255 100644 --- a/mmv1/products/compute/TargetInstance.yaml +++ b/mmv1/products/compute/TargetInstance.yaml @@ -38,15 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: post_create: 'templates/terraform/post_create/compute_target_instance_security_policy.go.tmpl' diff --git a/mmv1/products/compute/TargetSslProxy.yaml b/mmv1/products/compute/TargetSslProxy.yaml index 77c2e5fe4019..52944eb2bda5 100644 --- a/mmv1/products/compute/TargetSslProxy.yaml +++ b/mmv1/products/compute/TargetSslProxy.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/TargetTcpProxy.yaml b/mmv1/products/compute/TargetTcpProxy.yaml index b907719fec98..5f9d26969739 100644 --- a/mmv1/products/compute/TargetTcpProxy.yaml +++ b/mmv1/products/compute/TargetTcpProxy.yaml @@ -35,15 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/UrlMap.yaml b/mmv1/products/compute/UrlMap.yaml index 220e44837ec9..36371f2de68d 100644 --- a/mmv1/products/compute/UrlMap.yaml +++ b/mmv1/products/compute/UrlMap.yaml @@ -32,15 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/VpnGateway.yaml b/mmv1/products/compute/VpnGateway.yaml index 6b3996e130e0..6a069cc609a7 100644 --- a/mmv1/products/compute/VpnGateway.yaml +++ b/mmv1/products/compute/VpnGateway.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: examples: diff --git a/mmv1/products/compute/VpnTunnel.yaml b/mmv1/products/compute/VpnTunnel.yaml index 3ea736cda072..63ec456d1ba1 100644 --- a/mmv1/products/compute/VpnTunnel.yaml +++ b/mmv1/products/compute/VpnTunnel.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'compute#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: constants: 'templates/terraform/constants/vpn_tunnel.tmpl' diff --git a/mmv1/products/containerattached/Cluster.yaml b/mmv1/products/containerattached/Cluster.yaml index 6cb479944e3f..6ddaffda1ecb 100644 --- a/mmv1/products/containerattached/Cluster.yaml +++ b/mmv1/products/containerattached/Cluster.yaml @@ -41,14 +41,8 @@ async: type: 'OpAsync' operation: full_url: 'https://{{location}}-gkemulticloud.googleapis.com/v1/{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: constants: 'templates/terraform/constants/containerattached_cluster_diff.go.tmpl' pre_update: 'templates/terraform/pre_update/containerattached_update.go.tmpl' diff --git a/mmv1/products/databasemigrationservice/ConnectionProfile.yaml b/mmv1/products/databasemigrationservice/ConnectionProfile.yaml index 86dfe9d63612..3760f5ea5a6b 100644 --- a/mmv1/products/databasemigrationservice/ConnectionProfile.yaml +++ b/mmv1/products/databasemigrationservice/ConnectionProfile.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'database_migration_service_connection_profile_cloudsql' diff --git a/mmv1/products/databasemigrationservice/MigrationJob.yaml b/mmv1/products/databasemigrationservice/MigrationJob.yaml index 2dfadf6bd093..0dce9d4e2529 100644 --- a/mmv1/products/databasemigrationservice/MigrationJob.yaml +++ b/mmv1/products/databasemigrationservice/MigrationJob.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'database_migration_service_migration_job_mysql_to_mysql' diff --git a/mmv1/products/databasemigrationservice/PrivateConnection.yaml b/mmv1/products/databasemigrationservice/PrivateConnection.yaml index d8238cfe51fe..8b2187688ac6 100644 --- a/mmv1/products/databasemigrationservice/PrivateConnection.yaml +++ b/mmv1/products/databasemigrationservice/PrivateConnection.yaml @@ -37,8 +37,6 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: resource_inside_response: false custom_code: diff --git a/mmv1/products/datafusion/Instance.yaml b/mmv1/products/datafusion/Instance.yaml index 61518ffd4ad7..52382fe07da8 100644 --- a/mmv1/products/datafusion/Instance.yaml +++ b/mmv1/products/datafusion/Instance.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' diff --git a/mmv1/products/datafusion/product.yaml b/mmv1/products/datafusion/product.yaml index a09292369f4c..277558e38ec0 100644 --- a/mmv1/products/datafusion/product.yaml +++ b/mmv1/products/datafusion/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/dataplex/AspectType.yaml b/mmv1/products/dataplex/AspectType.yaml index c7480e61d786..ce718a8829ab 100644 --- a/mmv1/products/dataplex/AspectType.yaml +++ b/mmv1/products/dataplex/AspectType.yaml @@ -33,18 +33,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: exclude_import_test: true method_name_separator: ':' diff --git a/mmv1/products/dataplex/Datascan.yaml b/mmv1/products/dataplex/Datascan.yaml index c7d1e43e9fd6..ade7167e94b9 100644 --- a/mmv1/products/dataplex/Datascan.yaml +++ b/mmv1/products/dataplex/Datascan.yaml @@ -43,18 +43,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'data_scan_id' diff --git a/mmv1/products/dataplex/EntryGroup.yaml b/mmv1/products/dataplex/EntryGroup.yaml index 239f6977392b..a88d3d30812e 100644 --- a/mmv1/products/dataplex/EntryGroup.yaml +++ b/mmv1/products/dataplex/EntryGroup.yaml @@ -33,18 +33,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: exclude_import_test: true method_name_separator: ':' diff --git a/mmv1/products/dataplex/EntryType.yaml b/mmv1/products/dataplex/EntryType.yaml index 98573dfae7c7..eeaa25f4dd1e 100644 --- a/mmv1/products/dataplex/EntryType.yaml +++ b/mmv1/products/dataplex/EntryType.yaml @@ -33,18 +33,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: exclude_import_test: true method_name_separator: ':' diff --git a/mmv1/products/dataplex/Task.yaml b/mmv1/products/dataplex/Task.yaml index 85546ee8c272..e1a9b6bc0723 100644 --- a/mmv1/products/dataplex/Task.yaml +++ b/mmv1/products/dataplex/Task.yaml @@ -41,18 +41,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'task_id' diff --git a/mmv1/products/dataprocgdc/ApplicationEnvironment.yaml b/mmv1/products/dataprocgdc/ApplicationEnvironment.yaml index 1913e7a4498b..23c9f14f2aac 100644 --- a/mmv1/products/dataprocgdc/ApplicationEnvironment.yaml +++ b/mmv1/products/dataprocgdc/ApplicationEnvironment.yaml @@ -50,6 +50,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20419 - name: "dataprocgdc_applicationenvironment" primary_resource_id: "application-environment" vars: @@ -57,6 +58,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20419 update_verb: PATCH update_mask: true autogen_async: false diff --git a/mmv1/products/dataprocgdc/SparkApplication.yaml b/mmv1/products/dataprocgdc/SparkApplication.yaml index 55024aac6f31..92d81def627c 100644 --- a/mmv1/products/dataprocgdc/SparkApplication.yaml +++ b/mmv1/products/dataprocgdc/SparkApplication.yaml @@ -51,6 +51,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 - name: "dataprocgdc_sparkapplication" primary_resource_id: "spark-application" vars: @@ -59,6 +60,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 - name: "dataprocgdc_sparkapplication_pyspark" primary_resource_id: "spark-application" vars: @@ -66,6 +68,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 - name: "dataprocgdc_sparkapplication_sparkr" primary_resource_id: "spark-application" vars: @@ -73,6 +76,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 - name: "dataprocgdc_sparkapplication_sparksql" primary_resource_id: "spark-application" vars: @@ -80,6 +84,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 - name: "dataprocgdc_sparkapplication_sparksql_query_file" primary_resource_id: "spark-application" vars: @@ -87,6 +92,7 @@ examples: project: "my-project" test_vars_overrides: 'project': '"gdce-cluster-monitoring"' + skip_test: https://github.com/hashicorp/terraform-provider-google/issues/20418 base_url: projects/{{project}}/locations/{{location}}/serviceInstances/{{serviceinstance}}/sparkApplications create_url: projects/{{project}}/locations/{{location}}/serviceInstances/{{serviceinstance}}/sparkApplications?sparkApplicationId={{spark_application_id}} self_link: projects/{{project}}/locations/{{location}}/serviceInstances/{{serviceinstance}}/sparkApplications/{{spark_application_id}} diff --git a/mmv1/products/datastream/ConnectionProfile.yaml b/mmv1/products/datastream/ConnectionProfile.yaml index fc1b594225a2..bd6c77fe9326 100644 --- a/mmv1/products/datastream/ConnectionProfile.yaml +++ b/mmv1/products/datastream/ConnectionProfile.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'datastream_connection_profile_basic' diff --git a/mmv1/products/datastream/PrivateConnection.yaml b/mmv1/products/datastream/PrivateConnection.yaml index 5a192645fa00..26ab7b62ac52 100644 --- a/mmv1/products/datastream/PrivateConnection.yaml +++ b/mmv1/products/datastream/PrivateConnection.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/private_connection.go.tmpl' post_create: 'templates/terraform/post_create/private_connection.go.tmpl' diff --git a/mmv1/products/datastream/Stream.yaml b/mmv1/products/datastream/Stream.yaml index 71cb12278406..384886fd6e0b 100644 --- a/mmv1/products/datastream/Stream.yaml +++ b/mmv1/products/datastream/Stream.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/datastream_stream.go.tmpl' encoder: 'templates/terraform/encoders/datastream_stream.go.tmpl' diff --git a/mmv1/products/datastream/product.yaml b/mmv1/products/datastream/product.yaml index 593efcc3368e..a7a27a4d6486 100644 --- a/mmv1/products/datastream/product.yaml +++ b/mmv1/products/datastream/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/deploymentmanager/Deployment.yaml b/mmv1/products/deploymentmanager/Deployment.yaml index 3964e1cf0d27..84dc3f5fef61 100644 --- a/mmv1/products/deploymentmanager/Deployment.yaml +++ b/mmv1/products/deploymentmanager/Deployment.yaml @@ -52,15 +52,8 @@ async: type: 'OpAsync' operation: full_url: 'selfLink' - kind: 'deploymentmanager#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: # Custom diff to force new if 'preview' is true constants: 'templates/terraform/constants/deployment_manager_deployment.go.tmpl' diff --git a/mmv1/products/dialogflowcx/Agent.yaml b/mmv1/products/dialogflowcx/Agent.yaml index 8d3f2b006552..ef9fe6f7e087 100644 --- a/mmv1/products/dialogflowcx/Agent.yaml +++ b/mmv1/products/dialogflowcx/Agent.yaml @@ -164,7 +164,7 @@ properties: - name: 'useTimeoutBasedEndpointing' type: Boolean description: | - Use timeout based endpointing, interpreting endpointer sensitivy as seconds of timeout value. + Use timeout based endpointing, interpreting endpointer sensitivity as seconds of timeout value. - name: 'models' type: KeyValuePairs description: | diff --git a/mmv1/products/dialogflowcx/Environment.yaml b/mmv1/products/dialogflowcx/Environment.yaml index a453a2049cba..918753dcd8a4 100644 --- a/mmv1/products/dialogflowcx/Environment.yaml +++ b/mmv1/products/dialogflowcx/Environment.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: full_url: 'https://{{location}}-dialogflow.googleapis.com/v3/{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 20 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/dialogflow_set_location.go.tmpl' pre_read: 'templates/terraform/pre_create/dialogflow_set_location.go.tmpl' diff --git a/mmv1/products/dialogflowcx/Flow.yaml b/mmv1/products/dialogflowcx/Flow.yaml index c08b57be66bf..05d7643c9c54 100644 --- a/mmv1/products/dialogflowcx/Flow.yaml +++ b/mmv1/products/dialogflowcx/Flow.yaml @@ -587,7 +587,7 @@ properties: - name: 'useTimeoutBasedEndpointing' type: Boolean description: | - Use timeout based endpointing, interpreting endpointer sensitivy as seconds of timeout value. + Use timeout based endpointing, interpreting endpointer sensitivity as seconds of timeout value. - name: 'models' type: KeyValuePairs description: | diff --git a/mmv1/products/dialogflowcx/Version.yaml b/mmv1/products/dialogflowcx/Version.yaml index 161707d87adf..ac4245a25a65 100644 --- a/mmv1/products/dialogflowcx/Version.yaml +++ b/mmv1/products/dialogflowcx/Version.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: full_url: 'https://{{location}}-dialogflow.googleapis.com/v3/{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 20 delete_minutes: 20 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/dialogflow_set_location.go.tmpl' pre_read: 'templates/terraform/pre_create/dialogflow_set_location.go.tmpl' diff --git a/mmv1/products/discoveryengine/Schema.yaml b/mmv1/products/discoveryengine/Schema.yaml index 04f1780569b2..5737bd160de8 100644 --- a/mmv1/products/discoveryengine/Schema.yaml +++ b/mmv1/products/discoveryengine/Schema.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'discoveryengine_schema_basic' diff --git a/mmv1/products/discoveryengine/SearchEngine.yaml b/mmv1/products/discoveryengine/SearchEngine.yaml index 9ae92d9ae537..885afb9994e5 100644 --- a/mmv1/products/discoveryengine/SearchEngine.yaml +++ b/mmv1/products/discoveryengine/SearchEngine.yaml @@ -89,6 +89,7 @@ properties: enum_values: - 'GENERIC' - 'MEDIA' + - 'HEALTHCARE_FHIR' - name: 'displayName' type: String description: | diff --git a/mmv1/products/discoveryengine/TargetSite.yaml b/mmv1/products/discoveryengine/TargetSite.yaml index 1527a0177276..0409e7be4a21 100644 --- a/mmv1/products/discoveryengine/TargetSite.yaml +++ b/mmv1/products/discoveryengine/TargetSite.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: post_create: 'templates/terraform/post_create/set_computed_name.tmpl' custom_import: 'templates/terraform/custom_import/discoveryengine_targetsite_set_id.go.tmpl' diff --git a/mmv1/products/documentaiwarehouse/Location.yaml b/mmv1/products/documentaiwarehouse/Location.yaml index b424f13e5963..e4a1e5cc3e71 100644 --- a/mmv1/products/documentaiwarehouse/Location.yaml +++ b/mmv1/products/documentaiwarehouse/Location.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: exclude_sweeper: true examples: diff --git a/mmv1/products/edgecontainer/Cluster.yaml b/mmv1/products/edgecontainer/Cluster.yaml index acd3eb4f0f66..8ed259e74065 100644 --- a/mmv1/products/edgecontainer/Cluster.yaml +++ b/mmv1/products/edgecontainer/Cluster.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 480 update_minutes: 480 delete_minutes: 480 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'edgecontainer_cluster' diff --git a/mmv1/products/edgecontainer/NodePool.yaml b/mmv1/products/edgecontainer/NodePool.yaml index 37c3981c0c1c..c14264a5a675 100644 --- a/mmv1/products/edgecontainer/NodePool.yaml +++ b/mmv1/products/edgecontainer/NodePool.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 480 update_minutes: 480 delete_minutes: 480 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: # Skip the node-pool test as we only have limited machine resources diff --git a/mmv1/products/edgecontainer/VpnConnection.yaml b/mmv1/products/edgecontainer/VpnConnection.yaml index aa825f69604e..dc26f526a0cf 100644 --- a/mmv1/products/edgecontainer/VpnConnection.yaml +++ b/mmv1/products/edgecontainer/VpnConnection.yaml @@ -32,18 +32,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: # Skip the vpnconnection test as we only have limited machine resources, and the vpn connection is not a critical feature. diff --git a/mmv1/products/edgenetwork/Network.yaml b/mmv1/products/edgenetwork/Network.yaml index db95d7a5c025..fe3b4c849491 100644 --- a/mmv1/products/edgenetwork/Network.yaml +++ b/mmv1/products/edgenetwork/Network.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'edgenetwork_network' diff --git a/mmv1/products/edgenetwork/Subnet.yaml b/mmv1/products/edgenetwork/Subnet.yaml index dd977199de98..962e6a3008fb 100644 --- a/mmv1/products/edgenetwork/Subnet.yaml +++ b/mmv1/products/edgenetwork/Subnet.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'edgenetwork_subnet' diff --git a/mmv1/products/edgenetwork/product.yaml b/mmv1/products/edgenetwork/product.yaml index 5892960358ae..4c3fba14a40b 100644 --- a/mmv1/products/edgenetwork/product.yaml +++ b/mmv1/products/edgenetwork/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/filestore/Backup.yaml b/mmv1/products/filestore/Backup.yaml index 533f4bca4160..6ee2c18b8860 100644 --- a/mmv1/products/filestore/Backup.yaml +++ b/mmv1/products/filestore/Backup.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: error_abort_predicates: diff --git a/mmv1/products/filestore/Instance.yaml b/mmv1/products/filestore/Instance.yaml index bac39a7befc5..b3b113d1ef9d 100644 --- a/mmv1/products/filestore/Instance.yaml +++ b/mmv1/products/filestore/Instance.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_create: 'templates/terraform/pre_create/filestore_instance.go.tmpl' error_abort_predicates: diff --git a/mmv1/products/filestore/Snapshot.yaml b/mmv1/products/filestore/Snapshot.yaml index e426fbbfd483..f30d0d7603f7 100644 --- a/mmv1/products/filestore/Snapshot.yaml +++ b/mmv1/products/filestore/Snapshot.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: error_abort_predicates: diff --git a/mmv1/products/filestore/product.yaml b/mmv1/products/filestore/product.yaml index 39c9848d54b9..bec437c1fc1f 100644 --- a/mmv1/products/filestore/product.yaml +++ b/mmv1/products/filestore/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/firebase/AndroidApp.yaml b/mmv1/products/firebase/AndroidApp.yaml index f8e1e9052a77..6a35168fa7ab 100644 --- a/mmv1/products/firebase/AndroidApp.yaml +++ b/mmv1/products/firebase/AndroidApp.yaml @@ -42,14 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - appId - name diff --git a/mmv1/products/firebase/AppleApp.yaml b/mmv1/products/firebase/AppleApp.yaml index f0fc923504a7..07429052f5e0 100644 --- a/mmv1/products/firebase/AppleApp.yaml +++ b/mmv1/products/firebase/AppleApp.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - appId - name diff --git a/mmv1/products/firebase/Project.yaml b/mmv1/products/firebase/Project.yaml index e4dfc44fc188..6277a1f4c3d5 100644 --- a/mmv1/products/firebase/Project.yaml +++ b/mmv1/products/firebase/Project.yaml @@ -14,7 +14,7 @@ --- name: 'Project' description: | - A Google Cloud Firebase instance. This enables Firebase resources on a given google project. + A Google Cloud Firebase instance. This enables Firebase resources on a given Google Project. Since a FirebaseProject is actually also a GCP Project, a FirebaseProject uses underlying GCP identifiers (most importantly, the projectId) as its own for easy interop with GCP APIs. Once Firebase has been added to a Google Project it cannot be removed. @@ -46,14 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/firebase_project.go.tmpl' pre_create: 'templates/terraform/pre_create/firebase_project.go.tmpl' @@ -74,7 +68,7 @@ properties: - name: 'projectNumber' type: String description: | - The number of the google project that firebase is enabled on. + The number of the Google Project that Firebase is enabled on. min_version: 'beta' output: true - name: 'displayName' diff --git a/mmv1/products/firebase/WebApp.yaml b/mmv1/products/firebase/WebApp.yaml index e836e953194b..73ec4300de10 100644 --- a/mmv1/products/firebase/WebApp.yaml +++ b/mmv1/products/firebase/WebApp.yaml @@ -42,14 +42,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - appId - name diff --git a/mmv1/products/firebase/product.yaml b/mmv1/products/firebase/product.yaml index 515102129455..5fee07ee1b2c 100644 --- a/mmv1/products/firebase/product.yaml +++ b/mmv1/products/firebase/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/firebasedatabase/Instance.yaml b/mmv1/products/firebasedatabase/Instance.yaml index b7feea74ebd4..c09c50028e28 100644 --- a/mmv1/products/firebasedatabase/Instance.yaml +++ b/mmv1/products/firebasedatabase/Instance.yaml @@ -57,6 +57,8 @@ examples: - name: 'firebase_database_instance_default_database' primary_resource_id: 'default' min_version: 'beta' + # Wait for IAM propagation + external_providers: ["time"] vars: project_id: 'rtdb-project' test_env_vars: diff --git a/mmv1/products/firebaseextensions/Instance.yaml b/mmv1/products/firebaseextensions/Instance.yaml index 957b9f35dbea..71791e8e5c60 100644 --- a/mmv1/products/firebaseextensions/Instance.yaml +++ b/mmv1/products/firebaseextensions/Instance.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'firebase_extentions_instance_resize_image' diff --git a/mmv1/products/firebasehosting/CustomDomain.yaml b/mmv1/products/firebasehosting/CustomDomain.yaml index ec329d79a034..26541ebb608d 100644 --- a/mmv1/products/firebasehosting/CustomDomain.yaml +++ b/mmv1/products/firebasehosting/CustomDomain.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: post_create: 'templates/terraform/post_create/firebasehosting_custom_domain_wait_dns_verification.tmpl' test_check_destroy: 'templates/terraform/custom_check_destroy/firebasehosting_custom_domain_soft_delete.go.tmpl' @@ -561,7 +555,7 @@ properties: - name: 'reconciling' type: Boolean description: | - if true, indicates that Hosting's systems are attmepting to + if true, indicates that Hosting's systems are attempting to make the `CustomDomain`'s state match your preferred state. This is most frequently `true` when initially provisioning a `CustomDomain` or when creating a new SSL certificate to match an updated `cert_preference` diff --git a/mmv1/products/firebasehosting/Version.yaml b/mmv1/products/firebasehosting/Version.yaml index d25cfb666b9c..3e67be096cdf 100644 --- a/mmv1/products/firebasehosting/Version.yaml +++ b/mmv1/products/firebasehosting/Version.yaml @@ -25,7 +25,7 @@ base_url: 'sites/{{site_id}}/versions' self_link: 'sites/{{site_id}}/versions/{{version_id}}' create_url: 'sites/{{site_id}}/versions' exclude_delete: true - # not updatable +# not updatable immutable: true import_format: - 'sites/{{site_id}}/versions/{{version_id}}' @@ -46,6 +46,20 @@ examples: site_id: 'site-id' test_env_vars: project_id: 'PROJECT_NAME' + - name: 'firebasehosting_version_headers' + primary_resource_id: 'default' + min_version: 'beta' + vars: + site_id: 'site-id' + test_env_vars: + project_id: 'PROJECT_NAME' + - name: 'firebasehosting_version_headers_regex' + primary_resource_id: 'default' + min_version: 'beta' + vars: + site_id: 'site-id' + test_env_vars: + project_id: 'PROJECT_NAME' - name: 'firebasehosting_version_path' primary_resource_id: 'default' min_version: 'beta' @@ -126,45 +140,45 @@ properties: description: The user-supplied glob to match against the request URL path. min_version: 'beta' - exactly_one_of: - - 'glob' - - 'regex' + # exactly_one_of: + # - 'glob' + # - 'regex' - name: 'regex' type: String description: The user-supplied RE2 regular expression to match against the request URL path. min_version: 'beta' - exactly_one_of: - - 'glob' - - 'regex' + # exactly_one_of: + # - 'glob' + # - 'regex' - name: 'path' type: String description: The URL path to rewrite the request to. min_version: 'beta' - exactly_one_of: - - 'path' - - 'function' - - 'run' + # exactly_one_of: + # - 'path' + # - 'function' + # - 'run' - name: 'function' type: String description: The function to proxy requests to. Must match the exported function name exactly. min_version: 'beta' - exactly_one_of: - - 'path' - - 'function' - - 'run' + # exactly_one_of: + # - 'path' + # - 'function' + # - 'run' - name: 'run' type: NestedObject description: The request will be forwarded to Cloud Run. min_version: 'beta' - exactly_one_of: - - 'path' - - 'function' - - 'run' + # exactly_one_of: + # - 'path' + # - 'function' + # - 'run' properties: - name: 'serviceId' type: String @@ -194,18 +208,18 @@ properties: description: The user-supplied glob to match against the request URL path. min_version: 'beta' - exactly_one_of: - - 'glob' - - 'regex' + # exactly_one_of: + # - 'glob' + # - 'regex' - name: 'regex' type: String description: The user-supplied RE2 regular expression to match against the request URL path. min_version: 'beta' - exactly_one_of: - - 'glob' - - 'regex' + # exactly_one_of: + # - 'glob' + # - 'regex' - name: 'statusCode' type: Integer description: @@ -229,3 +243,34 @@ properties: ``` min_version: 'beta' required: true + - name: 'headers' + type: Array + description: | + An array of objects, where each object specifies a URL pattern that, if matched to the request URL path, + triggers Hosting to apply the specified custom response headers. + item_type: + description: | + A Header specifies a URL pattern that, if matched to the request URL path, triggers Hosting + to apply the specified custom response headers. + type: NestedObject + properties: + - name: 'glob' + type: String + description: + The user-supplied glob to match against the request URL path. + # exactly_one_of: + # - 'glob' + # - 'regex' + - name: 'regex' + type: String + description: + The user-supplied RE2 regular expression to match against the + request URL path. + # exactly_one_of: + # - 'glob' + # - 'regex' + - name: 'headers' + type: KeyValuePairs + description: | + The additional headers to add to the response. Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }. + required: true diff --git a/mmv1/products/firestore/Database.yaml b/mmv1/products/firestore/Database.yaml index 33f2e33f279d..ec8c89a9de18 100644 --- a/mmv1/products/firestore/Database.yaml +++ b/mmv1/products/firestore/Database.yaml @@ -45,14 +45,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_delete: 'templates/terraform/pre_delete/firestore_database.go.tmpl' examples: @@ -280,7 +274,7 @@ properties: This value should be the KMS key resource ID in the format of `projects/{project_id}/locations/{kms_location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}`. - How to retrive this resource ID is listed at + How to retrieve this resource ID is listed at https://cloud.google.com/kms/docs/getting-resource-ids#getting_the_id_for_a_key_and_version. required: true immutable: true diff --git a/mmv1/products/firestore/Field.yaml b/mmv1/products/firestore/Field.yaml index 7c0d9f3d9c6a..2506e9448a79 100644 --- a/mmv1/products/firestore/Field.yaml +++ b/mmv1/products/firestore/Field.yaml @@ -46,14 +46,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/firestore_field.go.tmpl' custom_delete: 'templates/terraform/custom_delete/firestore_field_delete.go.tmpl' diff --git a/mmv1/products/firestore/Index.yaml b/mmv1/products/firestore/Index.yaml index ce856d7b1f7c..7e7a548b7311 100644 --- a/mmv1/products/firestore/Index.yaml +++ b/mmv1/products/firestore/Index.yaml @@ -45,14 +45,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/firestore_index.go.tmpl' encoder: 'templates/terraform/encoders/index.go.tmpl' diff --git a/mmv1/products/gemini/CodeRepositoryIndex.yaml b/mmv1/products/gemini/CodeRepositoryIndex.yaml new file mode 100644 index 000000000000..62cb5236c845 --- /dev/null +++ b/mmv1/products/gemini/CodeRepositoryIndex.yaml @@ -0,0 +1,103 @@ +# Copyright 2024 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: CodeRepositoryIndex +description: The resource for managing Code Repository Index for Gemini Code Assist. +min_version: 'beta' +base_url: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes +self_link: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index_id}} +create_url: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes?codeRepositoryIndexId={{code_repository_index_id}} +update_verb: 'PATCH' +update_mask: true +id_format: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index_id}} +import_format: + - projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index_id}} +mutex: 'projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index_id}}' +examples: + - name: "gemini_code_repository_index_basic" + min_version: 'beta' + primary_resource_id: "example" + test_vars_overrides: + cri_id: '"cri-example"' + exclude_test: true +timeouts: + insert_minutes: 90 + update_minutes: 90 + delete_minutes: 90 +autogen_async: true +async: + operation: + timeouts: + insert_minutes: 90 + update_minutes: 90 + delete_minutes: 90 + base_url: "{{op_id}}" + actions: + - create + - delete + - update + type: OpAsync + result: + resource_inside_response: true + include_project: false +error_retry_predicates: + - 'transport_tpg.IsCodeRepositoryIndexUnreadyError' + - 'transport_tpg.IsRepositoryGroupQueueError' +parameters: + - name: location + type: String + description: The location of the Code Repository Index, for example `us-central1`. + immutable: true + url_param_only: true + required: true + - name: codeRepositoryIndexId + type: String + description: Required. Id of the Code Repository Index. + immutable: true + url_param_only: true + required: true +properties: + - name: updateTime + type: String + description: Output only. Update time stamp. + output: true + - name: state + type: String + description: |- + Output only. Code Repository Index instance State. + Possible values: + STATE_UNSPECIFIED + CREATING + ACTIVE + DELETING + SUSPENDED + output: true + - name: labels + type: KeyValueLabels + description: Optional. Labels as key value pairs. + - name: kmsKey + type: String + description: |- + Optional. Immutable. Customer-managed encryption key name, in the format + projects/*/locations/*/keyRings/*/cryptoKeys/*. + immutable: true + - name: name + type: String + description: Immutable. Identifier. Name of Code Repository Index. + output: true + immutable: true + - name: createTime + type: String + description: Output only. Create time stamp. + output: true diff --git a/mmv1/products/gemini/RepositoryGroup.yaml b/mmv1/products/gemini/RepositoryGroup.yaml new file mode 100644 index 000000000000..e6c8e1513ec5 --- /dev/null +++ b/mmv1/products/gemini/RepositoryGroup.yaml @@ -0,0 +1,131 @@ +# Copyright 2024 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: RepositoryGroup +description: The resource for managing Repository Group for Gemini Code Assist. +min_version: 'beta' +base_url: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups +self_link: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups/{{repository_group_id}} +create_url: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups?repositoryGroupId={{repository_group_id}} +update_verb: 'PATCH' +update_mask: true +id_format: projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups/{{repository_group_id}} +import_format: + - projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups/{{repository_group_id}} +mutex: 'projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}' +examples: + - name: "gemini_repository_group_basic" + min_version: 'beta' + primary_resource_id: "example" + primary_resource_name: 'acctest.BootstrapSharedCodeRepositoryIndex(t, "basic-rg-gen-example", "us-central1", "", map[string]string{}), fmt.Sprintf("tf-test-gen-repository-group-%s", context["random_suffix"])' + vars: + repository_group_id: "gen-repository-group-" + git_repository_link_id: 'example-git-repository-link-id' + cri_id: "cri-example" + repository_resource: "projects/example-project/locations/us-central1/connections/example-connection/gitRepositoryLinks/example-repo" + connection_id: "example-connection-id" + test_vars_overrides: + git_repository_link_id: 'acctest.BootstrapGitRepository(t, "basic", "us-central1", "https://github.com/CC-R-github-robot/tf-test.git", acctest.BootstrapDeveloperConnection(t, "basic", "us-central1", "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648))' + cri_id: 'acctest.BootstrapSharedCodeRepositoryIndex(t, "basic-rg-gen-example", "us-central1", "", map[string]string{})' + repository_resource: '"projects/"+envvar.GetTestProjectFromEnv()+"/locations/us-central1/connections/"+acctest.BootstrapDeveloperConnection(t, "basic", "us-central1", "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648)+"/gitRepositoryLinks/"+acctest.BootstrapGitRepository(t, "basic", "us-central1", "https://github.com/CC-R-github-robot/tf-test.git", acctest.BootstrapDeveloperConnection(t, "basic", "us-central1", "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648))' + connection_id: 'acctest.BootstrapDeveloperConnection(t, "basic", "us-central1", "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648)' + exclude_test: true +timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 +autogen_async: true +async: + operation: + timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 + base_url: "{{op_id}}" + actions: + - create + - delete + - update + type: OpAsync + result: + resource_inside_response: true + include_project: false +iam_policy: + min_version: 'beta' + parent_resource_attribute: 'repository_group_id' + method_name_separator: ':' + fetch_iam_policy_verb: 'GET' + set_iam_policy_verb: 'POST' + import_format: + - 'projects/{{project}}/locations/{{location}}/codeRepositoryIndexes/{{code_repository_index}}/repositoryGroups/{{repository_group_id}}' + - '{{repository_group_id}}' + allowed_iam_role: 'roles/cloudaicompanion.repositoryGroupsUser' +error_retry_predicates: + - 'transport_tpg.IsCodeRepositoryIndexUnreadyError' + - 'transport_tpg.IsRepositoryGroupQueueError' +parameters: + - name: location + type: String + description: The location of the Code Repository Index, for example `us-central1`. + immutable: true + url_param_only: true + required: true + - name: codeRepositoryIndex + type: String + description: Required. Id of the Code Repository Index. + immutable: true + url_param_only: true + required: true + - name: repositoryGroupId + type: String + description: Required. Id of the Repository Group. + immutable: true + url_param_only: true + required: true +properties: + - name: repositories + type: Array + description: Required. List of repositories to group + required: true + item_type: + type: NestedObject + properties: + - name: resource + type: String + description: |- + Required. The DeveloperConnect repository full resource name, relative resource name + or resource URL to be indexed. + required: true + - name: branchPattern + type: String + description: |- + Required. The Git branch pattern used for indexing in RE2 syntax. + See https://github.com/google/re2/wiki/syntax for syntax. + required: true + - name: name + type: String + description: Immutable. Identifier. name of resource + output: true + immutable: true + - name: createTime + type: String + description: Output only. Create time stamp + output: true + - name: updateTime + type: String + description: Output only. Update time stamp + output: true + - name: labels + type: KeyValueLabels + description: Optional. Labels as key value pairs diff --git a/mmv1/products/gemini/product.yaml b/mmv1/products/gemini/product.yaml new file mode 100644 index 000000000000..e9b03fba5526 --- /dev/null +++ b/mmv1/products/gemini/product.yaml @@ -0,0 +1,21 @@ +# Copyright 2024 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: Gemini +display_name: Gemini for Google Cloud +scopes: + - https://www.googleapis.com/auth/cloud-platform +versions: + - base_url: https://cloudaicompanion.googleapis.com/v1/ + name: 'beta' diff --git a/mmv1/products/gkebackup/BackupPlan.yaml b/mmv1/products/gkebackup/BackupPlan.yaml index 7873f69313b2..9910c9df2d31 100644 --- a/mmv1/products/gkebackup/BackupPlan.yaml +++ b/mmv1/products/gkebackup/BackupPlan.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' diff --git a/mmv1/products/gkebackup/RestorePlan.yaml b/mmv1/products/gkebackup/RestorePlan.yaml index 9d19cc03ea2f..f7cb3381cb38 100644 --- a/mmv1/products/gkebackup/RestorePlan.yaml +++ b/mmv1/products/gkebackup/RestorePlan.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' diff --git a/mmv1/products/gkebackup/product.yaml b/mmv1/products/gkebackup/product.yaml index 82ddf2e41c46..095bc8a5dc8a 100644 --- a/mmv1/products/gkebackup/product.yaml +++ b/mmv1/products/gkebackup/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/gkehub/Membership.yaml b/mmv1/products/gkehub/Membership.yaml index b49422564054..ef242bb3e385 100644 --- a/mmv1/products/gkehub/Membership.yaml +++ b/mmv1/products/gkehub/Membership.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'membership_id' diff --git a/mmv1/products/gkehub2/Feature.yaml b/mmv1/products/gkehub2/Feature.yaml index de7207174310..c2e20ba91f57 100644 --- a/mmv1/products/gkehub2/Feature.yaml +++ b/mmv1/products/gkehub2/Feature.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub2#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' @@ -484,7 +477,7 @@ properties: type: Enum description: 'Configures the manner in which the template library is installed on the cluster.' enum_values: - - 'INSTALATION_UNSPECIFIED' + - 'INSTALLATION_UNSPECIFIED' - 'NOT_INSTALLED' - 'ALL' - name: 'bundles' diff --git a/mmv1/products/gkehub2/Fleet.yaml b/mmv1/products/gkehub2/Fleet.yaml index a15f6ebb3800..63234b2a9350 100644 --- a/mmv1/products/gkehub2/Fleet.yaml +++ b/mmv1/products/gkehub2/Fleet.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: examples: - name: 'gkehub_fleet_basic' diff --git a/mmv1/products/gkehub2/MembershipBinding.yaml b/mmv1/products/gkehub2/MembershipBinding.yaml index 80966cbe8131..1d9e01c35a42 100644 --- a/mmv1/products/gkehub2/MembershipBinding.yaml +++ b/mmv1/products/gkehub2/MembershipBinding.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: # Skip sweeper gen since this is a child resource. exclude_sweeper: true diff --git a/mmv1/products/gkehub2/MembershipRBACRoleBinding.yaml b/mmv1/products/gkehub2/MembershipRBACRoleBinding.yaml index 2c9548bb7e80..a98bee979daf 100644 --- a/mmv1/products/gkehub2/MembershipRBACRoleBinding.yaml +++ b/mmv1/products/gkehub2/MembershipRBACRoleBinding.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: # Skip sweeper gen since this is a child resource. exclude_sweeper: true diff --git a/mmv1/products/gkehub2/Namespace.yaml b/mmv1/products/gkehub2/Namespace.yaml index 8c858c909485..9e9a8799ad1d 100644 --- a/mmv1/products/gkehub2/Namespace.yaml +++ b/mmv1/products/gkehub2/Namespace.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: # Skip sweeper gen since this is a child resource. exclude_sweeper: true diff --git a/mmv1/products/gkehub2/Scope.yaml b/mmv1/products/gkehub2/Scope.yaml index 6c5df3aa5a04..e9ba4268755a 100644 --- a/mmv1/products/gkehub2/Scope.yaml +++ b/mmv1/products/gkehub2/Scope.yaml @@ -39,15 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'scope_id' diff --git a/mmv1/products/gkehub2/ScopeRBACRoleBinding.yaml b/mmv1/products/gkehub2/ScopeRBACRoleBinding.yaml index d51fa9845a1e..2b960e60a0fa 100644 --- a/mmv1/products/gkehub2/ScopeRBACRoleBinding.yaml +++ b/mmv1/products/gkehub2/ScopeRBACRoleBinding.yaml @@ -40,15 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkehub#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error/errors' - message: 'message' custom_code: # Skip sweeper gen since this is a child resource. exclude_sweeper: true diff --git a/mmv1/products/gkeonprem/BareMetalAdminCluster.yaml b/mmv1/products/gkeonprem/BareMetalAdminCluster.yaml index 14778db7250d..517a96b4b48c 100644 --- a/mmv1/products/gkeonprem/BareMetalAdminCluster.yaml +++ b/mmv1/products/gkeonprem/BareMetalAdminCluster.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: taint_resource_on_failed_create: true examples: diff --git a/mmv1/products/gkeonprem/BareMetalCluster.yaml b/mmv1/products/gkeonprem/BareMetalCluster.yaml index 928cf80ed860..faaa150259f8 100644 --- a/mmv1/products/gkeonprem/BareMetalCluster.yaml +++ b/mmv1/products/gkeonprem/BareMetalCluster.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: taint_resource_on_failed_create: true examples: diff --git a/mmv1/products/gkeonprem/BareMetalNodePool.yaml b/mmv1/products/gkeonprem/BareMetalNodePool.yaml index 5bd219eee507..1b0f9d92d8a4 100644 --- a/mmv1/products/gkeonprem/BareMetalNodePool.yaml +++ b/mmv1/products/gkeonprem/BareMetalNodePool.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: exclude_sweeper: true taint_resource_on_failed_create: true diff --git a/mmv1/products/gkeonprem/VmwareCluster.yaml b/mmv1/products/gkeonprem/VmwareCluster.yaml index 4c1f8cd97667..641832e1aad4 100644 --- a/mmv1/products/gkeonprem/VmwareCluster.yaml +++ b/mmv1/products/gkeonprem/VmwareCluster.yaml @@ -34,15 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: taint_resource_on_failed_create: true examples: diff --git a/mmv1/products/gkeonprem/VmwareNodePool.yaml b/mmv1/products/gkeonprem/VmwareNodePool.yaml index 9bfdf5f7e514..6207952441b8 100644 --- a/mmv1/products/gkeonprem/VmwareNodePool.yaml +++ b/mmv1/products/gkeonprem/VmwareNodePool.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: taint_resource_on_failed_create: true examples: diff --git a/mmv1/products/gkeonprem/product.yaml b/mmv1/products/gkeonprem/product.yaml index 76ac5357f515..ceb67735117b 100644 --- a/mmv1/products/gkeonprem/product.yaml +++ b/mmv1/products/gkeonprem/product.yaml @@ -25,12 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - kind: 'gkeonprem#operation' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/iam2/AccessBoundaryPolicy.yaml b/mmv1/products/iam2/AccessBoundaryPolicy.yaml index 0d6023b647e6..d2978b839378 100644 --- a/mmv1/products/iam2/AccessBoundaryPolicy.yaml +++ b/mmv1/products/iam2/AccessBoundaryPolicy.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: # Skipping sweeper since this is a child resource exclude_sweeper: true diff --git a/mmv1/products/iam2/DenyPolicy.yaml b/mmv1/products/iam2/DenyPolicy.yaml index 82c4c1ed7d8d..6c12f8053dee 100644 --- a/mmv1/products/iam2/DenyPolicy.yaml +++ b/mmv1/products/iam2/DenyPolicy.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'iam_deny_policy_basic' diff --git a/mmv1/products/iam2/product.yaml b/mmv1/products/iam2/product.yaml index 4d19b8a1bd16..edb612dd355e 100644 --- a/mmv1/products/iam2/product.yaml +++ b/mmv1/products/iam2/product.yaml @@ -26,11 +26,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/iam3/FoldersPolicyBinding.yaml b/mmv1/products/iam3/FoldersPolicyBinding.yaml index f4bd018dbada..84f1b19b3061 100644 --- a/mmv1/products/iam3/FoldersPolicyBinding.yaml +++ b/mmv1/products/iam3/FoldersPolicyBinding.yaml @@ -17,8 +17,7 @@ description: A policy binding to a folder references: guides: 'Apply a policy binding': 'https://cloud.google.com/iam/docs/principal-access-boundary-policies-create#create_binding' - api: 'https://cloud.google.com/iam/docs/reference/rest/v3beta/folders.locations.policyBindings' -min_version: 'beta' + api: 'https://cloud.google.com/iam/docs/reference/rest/v3/folders.locations.policyBindings' id_format: 'folders/{{folder}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' base_url: 'folders/{{folder}}/locations/{{location}}/policyBindings' self_link: 'folders/{{folder}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' @@ -39,17 +38,11 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' + include_project: true examples: - name: 'iam_folders_policy_binding' - min_version: 'beta' primary_resource_id: 'my-folder-binding' test_env_vars: org_id: 'ORG_ID' diff --git a/mmv1/products/iam3/OrganizationsPolicyBinding.yaml b/mmv1/products/iam3/OrganizationsPolicyBinding.yaml index bc2c103f2ed7..1f0bebfc007f 100644 --- a/mmv1/products/iam3/OrganizationsPolicyBinding.yaml +++ b/mmv1/products/iam3/OrganizationsPolicyBinding.yaml @@ -17,8 +17,7 @@ description: A policy binding to an organizations references: guides: 'Apply a policy binding': 'https://cloud.google.com/iam/docs/principal-access-boundary-policies-create#create_binding' - api: 'https://cloud.google.com/iam/docs/reference/rest/v3beta/organizations.locations.policyBindings' -min_version: 'beta' + api: 'https://cloud.google.com/iam/docs/reference/rest/v3/organizations.locations.policyBindings' id_format: 'organizations/{{organization}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' base_url: 'organizations/{{organization}}/locations/{{location}}/policyBindings' self_link: 'organizations/{{organization}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' @@ -39,17 +38,11 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' + include_project: true examples: - name: 'iam_organizations_policy_binding' - min_version: 'beta' primary_resource_id: 'my-org-binding' test_env_vars: org_id: 'ORG_ID' diff --git a/mmv1/products/iam3/PrincipalAccessBoundaryPolicy.yaml b/mmv1/products/iam3/PrincipalAccessBoundaryPolicy.yaml index 37c47fec2230..95042c5fa594 100644 --- a/mmv1/products/iam3/PrincipalAccessBoundaryPolicy.yaml +++ b/mmv1/products/iam3/PrincipalAccessBoundaryPolicy.yaml @@ -17,8 +17,7 @@ description: An IAM Principal Access Boundary Policy resource references: guides: 'Create and apply Principal Access Boundaries': 'https://cloud.google.com/iam/docs/principal-access-boundary-policies-create' - api: 'https://cloud.google.com/iam/docs/reference/rest/v3beta/organizations.locations.principalAccessBoundaryPolicies' -min_version: 'beta' + api: 'https://cloud.google.com/iam/docs/reference/rest/v3/organizations.locations.principalAccessBoundaryPolicies' id_format: 'organizations/{{organization}}/locations/{{location}}/principalAccessBoundaryPolicies/{{principal_access_boundary_policy_id}}' base_url: 'organizations/{{organization}}/locations/{{location}}/principalAccessBoundaryPolicies' self_link: 'organizations/{{organization}}/locations/{{location}}/principalAccessBoundaryPolicies/{{principal_access_boundary_policy_id}}' @@ -37,17 +36,11 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' + include_project: true examples: - name: 'iam_principal_access_boundary_policy' - min_version: 'beta' primary_resource_id: 'my-pab-policy' test_env_vars: org_id: 'ORG_ID' diff --git a/mmv1/products/iam3/ProjectsPolicyBinding.yaml b/mmv1/products/iam3/ProjectsPolicyBinding.yaml new file mode 100644 index 000000000000..afa18466722b --- /dev/null +++ b/mmv1/products/iam3/ProjectsPolicyBinding.yaml @@ -0,0 +1,173 @@ +# Copyright 2024 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: 'ProjectsPolicyBinding' +description: A policy binding to a Project +references: + guides: + 'Apply a policy binding': 'https://cloud.google.com/iam/docs/principal-access-boundary-policies-create#create_binding' + api: 'https://cloud.google.com/iam/docs/reference/rest/v3/projects.locations.policyBindings' +id_format: 'projects/{{project}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/policyBindings' +self_link: 'projects/{{project}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/policyBindings?policyBindingId={{policy_binding_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/policyBindings/{{policy_binding_id}}' +timeouts: + insert_minutes: 20 + update_minutes: 20 + delete_minutes: 20 +custom_code: + post_delete: 'templates/terraform/post_delete/sleep.go.tmpl' +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +examples: + - name: 'iam_projects_policy_binding' + primary_resource_id: 'my-project-binding' + test_env_vars: + org_id: 'ORG_ID' + vars: + pab_policy_id: 'my-pab-policy' + display_name: 'test project binding' + project_binding_id: 'test-project-binding' +parameters: + - name: 'location' + type: String + description: | + The location of the Policy Binding + url_param_only: true + required: true + immutable: true + - name: 'policyBindingId' + type: String + description: | + The Policy Binding ID. + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: | + The name of the policy binding in the format `{binding_parent/locations/{location}/policyBindings/{policy_binding_id}` + output: true + - name: 'uid' + type: String + description: | + Output only. The globally unique ID of the policy binding. Assigned when the policy binding is created. + output: true + - name: 'etag' + type: Fingerprint + description: | + Optional. The etag for the policy binding. If this is provided on update, it must match the server's etag. + output: true + - name: 'displayName' + type: String + description: | + Optional. The description of the policy binding. Must be less than or equal to 63 characters. + - name: 'annotations' + type: KeyValueAnnotations + description: | + Optional. User defined annotations. See https://google.aip.dev/148#annotations for more details such as format and size limitations + - name: 'target' + type: NestedObject + description: | + Target is the full resource name of the resource to which the policy will be bound. Immutable once set. + required: true + properties: + - name: 'principalSet' + type: String + description: | + Required. Immutable. The resource name of the policy to be bound. + The binding parent and policy must belong to the same Organization (or Project). + immutable: true + - name: 'policyKind' + type: String + description: | + Immutable. The kind of the policy to attach in this binding. This + field must be one of the following: - Left empty (will be automatically set + to the policy kind) - The input policy kind Possible values: POLICY_KIND_UNSPECIFIED PRINCIPAL_ACCESS_BOUNDARY ACCESS + immutable: true + - name: 'policy' + type: String + description: | + Required. Immutable. The resource name of the policy to be bound. The binding parent and policy must belong to the same Organization (or Project). + required: true + immutable: true + - name: 'policyUid' + type: String + description: | + Output only. The globally unique ID of the policy to be bound. + output: true + - name: 'condition' + type: NestedObject + description: | + Represents a textual expression in the Common Expression Language + (CEL) syntax. CEL is a C-like expression language. The syntax and semantics of + CEL are documented at https://github.com/google/cel-spec. + Example (Comparison): + title: \"Summary size limit\" + description: \"Determines if a summary is less than 100 chars\" + expression: \"document.summary.size() < 100\" + Example + (Equality): + title: \"Requestor is owner\" + description: \"Determines if requestor is the document owner\" + expression: \"document.owner == request.auth.claims.email\" Example + (Logic): + title: \"Public documents\" + description: \"Determine whether the document should be publicly visible\" + expression: \"document.type != 'private' && document.type != 'internal'\" + Example (Data Manipulation): + title: \"Notification string\" + description: \"Create a notification string with a timestamp.\" + expression: \"'New message received at ' + string(document.create_time)\" + The exact variables and functions that may be referenced within an expression are + determined by the service that evaluates it. See the service documentation for + additional information. + properties: + - name: 'expression' + type: String + description: | + Textual representation of an expression in Common Expression Language syntax. + - name: 'title' + type: String + description: | + Optional. Title for the expression, i.e. a short string describing its purpose. This can be used e.g. in UIs which allow to enter the expression. + - name: 'description' + type: String + description: | + Optional. Description of the expression. This is a longer text which describes the expression, e.g. when hovered over it in a UI. + - name: 'location' + type: String + description: | + Optional. String indicating the location of the expression for error reporting, e.g. a file name and a position in the file. + - name: 'createTime' + type: String + description: | + Output only. The time when the policy binding was created. + output: true + - name: 'updateTime' + type: String + description: | + Output only. The time when the policy binding was most recently updated. + output: true diff --git a/mmv1/products/iam3/product.yaml b/mmv1/products/iam3/product.yaml index 1ca1d7d66f38..66fe78a52048 100644 --- a/mmv1/products/iam3/product.yaml +++ b/mmv1/products/iam3/product.yaml @@ -17,5 +17,7 @@ display_name: 'Cloud IAM' versions: - name: 'beta' base_url: 'https://iam.googleapis.com/v3beta/' + - name: 'ga' + base_url: 'https://iam.googleapis.com/v3/' scopes: - 'https://www.googleapis.com/auth/iam' diff --git a/mmv1/products/iambeta/WorkloadIdentityPool.yaml b/mmv1/products/iambeta/WorkloadIdentityPool.yaml index 8ae5ff1f08b5..4ab9768f124d 100644 --- a/mmv1/products/iambeta/WorkloadIdentityPool.yaml +++ b/mmv1/products/iambeta/WorkloadIdentityPool.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/iam_workload_identity_pool.go.tmpl' decoder: 'templates/terraform/decoders/treat_deleted_state_as_gone.go.tmpl' diff --git a/mmv1/products/iambeta/WorkloadIdentityPoolProvider.yaml b/mmv1/products/iambeta/WorkloadIdentityPoolProvider.yaml index 13400e181be5..177fbf91c251 100644 --- a/mmv1/products/iambeta/WorkloadIdentityPoolProvider.yaml +++ b/mmv1/products/iambeta/WorkloadIdentityPoolProvider.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/iam_workload_identity_pool_provider.go.tmpl' decoder: 'templates/terraform/decoders/treat_deleted_state_as_gone.go.tmpl' diff --git a/mmv1/products/iambeta/product.yaml b/mmv1/products/iambeta/product.yaml index 755c3e25c7ee..b85cd7542700 100644 --- a/mmv1/products/iambeta/product.yaml +++ b/mmv1/products/iambeta/product.yaml @@ -26,11 +26,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/iamworkforcepool/WorkforcePool.yaml b/mmv1/products/iamworkforcepool/WorkforcePool.yaml index 1dfdbebb02a0..b34dcaa30b95 100644 --- a/mmv1/products/iamworkforcepool/WorkforcePool.yaml +++ b/mmv1/products/iamworkforcepool/WorkforcePool.yaml @@ -41,14 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/iam_workforce_pool.go.tmpl' decoder: 'templates/terraform/decoders/treat_deleted_state_as_gone.go.tmpl' diff --git a/mmv1/products/iamworkforcepool/WorkforcePoolProvider.yaml b/mmv1/products/iamworkforcepool/WorkforcePoolProvider.yaml index 36249df1d7fe..2694ea79bda1 100644 --- a/mmv1/products/iamworkforcepool/WorkforcePoolProvider.yaml +++ b/mmv1/products/iamworkforcepool/WorkforcePoolProvider.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/iam_workforce_pool_provider.go.tmpl' decoder: 'templates/terraform/decoders/treat_deleted_state_as_gone.go.tmpl' diff --git a/mmv1/products/iamworkforcepool/product.yaml b/mmv1/products/iamworkforcepool/product.yaml index 8cdfa250aaa3..3f6c2b4021d4 100644 --- a/mmv1/products/iamworkforcepool/product.yaml +++ b/mmv1/products/iamworkforcepool/product.yaml @@ -26,11 +26,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/identityplatform/Config.yaml b/mmv1/products/identityplatform/Config.yaml index 57a574c05edf..32cfe84ade3d 100644 --- a/mmv1/products/identityplatform/Config.yaml +++ b/mmv1/products/identityplatform/Config.yaml @@ -49,6 +49,7 @@ examples: vars: instance_name: 'memory-cache' project_id: 'my-project' + quota_start_time: '2014-10-02T15:01:23Z' test_env_vars: org_id: 'ORG_ID' billing_acct: 'BILLING_ACCT' @@ -228,20 +229,29 @@ properties: - name: 'signUpQuotaConfig' type: NestedObject description: | - Quota for the Signup endpoint, if overwritten. Signup quota is measured in sign ups per project per hour per IP. + Quota for the Signup endpoint, if overwritten. Signup quota is measured in sign ups per project per hour per IP. None of quota, startTime, or quotaDuration can be skipped. properties: - name: 'quota' type: Integer description: | - A sign up APIs quota that customers can override temporarily. + A sign up APIs quota that customers can override temporarily. Value can be in between 1 and 1000. + required_with: + - quota.0.signUpQuotaConfig.0.startTime + - quota.0.signUpQuotaConfig.0.quotaDuration - name: 'startTime' type: Time description: | When this quota will take affect. + required_with: + - quota.0.signUpQuotaConfig.0.quota + - quota.0.signUpQuotaConfig.0.quotaDuration - name: 'quotaDuration' type: String description: | How long this quota will be active for. It is measurred in seconds, e.g., Example: "9.615s". + required_with: + - quota.0.signUpQuotaConfig.0.startTime + - quota.0.signUpQuotaConfig.0.quota - name: 'authorizedDomains' type: Array description: | diff --git a/mmv1/products/integrationconnectors/Connection.yaml b/mmv1/products/integrationconnectors/Connection.yaml index 63364032410a..da85803f02a9 100644 --- a/mmv1/products/integrationconnectors/Connection.yaml +++ b/mmv1/products/integrationconnectors/Connection.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 50 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/integration_connectors_connection.go.tmpl' post_create: 'templates/terraform/post_create/integration_connectors_connection.go.tmpl' @@ -143,7 +137,7 @@ properties: - name: 'description' type: String description: | - An arbitrary description for the Conection. + An arbitrary description for the Connection. - name: 'labels' type: KeyValueLabels description: | @@ -215,12 +209,12 @@ properties: - name: 'encryptionKeyValue' type: NestedObject description: | - Encription key value of configVariable. + Encryption key value of configVariable. properties: - name: 'type' type: Enum description: | - Type of Encription Key + Type of Encryption Key required: true enum_values: - 'GOOGLE_MANAGED' @@ -287,12 +281,12 @@ properties: - name: 'encryptionKeyValue' type: NestedObject description: | - Encription key value of configVariable. + Encryption key value of configVariable. properties: - name: 'type' type: Enum description: | - Type of Encription Key + Type of Encryption Key required: true enum_values: - 'GOOGLE_MANAGED' @@ -691,12 +685,12 @@ properties: - name: 'encryptionKeyValue' type: NestedObject description: | - Encription key value of configVariable + Encryption key value of configVariable properties: - name: 'type' type: Enum description: | - Type of Encription Key + Type of Encryption Key enum_values: - 'GOOGLE_MANAGED' - 'CUSTOMER_MANAGED' @@ -810,12 +804,12 @@ properties: - name: 'encryptionKeyValue' type: NestedObject description: | - Encription key value of configVariable + Encryption key value of configVariable properties: - name: 'type' type: Enum description: | - Type of Encription Key + Type of Encryption Key enum_values: - 'GOOGLE_MANAGED' - 'CUSTOMER_MANAGED' @@ -890,7 +884,7 @@ properties: - name: 'encryptionKeyValue' type: NestedObject description: | - Encription key value of configVariable. + Encryption key value of configVariable. properties: - name: 'type' type: Enum diff --git a/mmv1/products/integrationconnectors/EndpointAttachment.yaml b/mmv1/products/integrationconnectors/EndpointAttachment.yaml index a604983fb363..8f896b50331f 100644 --- a/mmv1/products/integrationconnectors/EndpointAttachment.yaml +++ b/mmv1/products/integrationconnectors/EndpointAttachment.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'integration_connectors_endpoint_attachment' diff --git a/mmv1/products/integrationconnectors/ManagedZone.yaml b/mmv1/products/integrationconnectors/ManagedZone.yaml index ccc6b5d59cc7..f98c8e652072 100644 --- a/mmv1/products/integrationconnectors/ManagedZone.yaml +++ b/mmv1/products/integrationconnectors/ManagedZone.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 5 update_minutes: 5 delete_minutes: 5 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'integration_connectors_managed_zone' diff --git a/mmv1/products/logging/LinkedDataset.yaml b/mmv1/products/logging/LinkedDataset.yaml index 03d3e6fb2b08..bba17c5aecc8 100644 --- a/mmv1/products/logging/LinkedDataset.yaml +++ b/mmv1/products/logging/LinkedDataset.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/logging_linked_dataset.go.tmpl' # Skip sweeper gen since this is a child resource. diff --git a/mmv1/products/looker/Instance.yaml b/mmv1/products/looker/Instance.yaml index 099675827187..e0e7d93acb77 100644 --- a/mmv1/products/looker/Instance.yaml +++ b/mmv1/products/looker/Instance.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' exclude_sweeper: true error_abort_predicates: @@ -412,6 +406,9 @@ properties: - LOOKER_CORE_STANDARD_ANNUAL: subscription standard instance - LOOKER_CORE_ENTERPRISE_ANNUAL: subscription enterprise instance - LOOKER_CORE_EMBED_ANNUAL: subscription embed instance + - LOOKER_CORE_NONPROD_STANDARD_ANNUAL: nonprod subscription standard instance + - LOOKER_CORE_NONPROD_ENTERPRISE_ANNUAL: nonprod subscription enterprise instance + - LOOKER_CORE_NONPROD_EMBED_ANNUAL: nonprod subscription embed instance immutable: true default_value: "LOOKER_CORE_TRIAL" enum_values: @@ -420,6 +417,9 @@ properties: - 'LOOKER_CORE_STANDARD_ANNUAL' - 'LOOKER_CORE_ENTERPRISE_ANNUAL' - 'LOOKER_CORE_EMBED_ANNUAL' + - 'LOOKER_CORE_NONPROD_STANDARD_ANNUAL' + - 'LOOKER_CORE_NONPROD_ENTERPRISE_ANNUAL' + - 'LOOKER_CORE_NONPROD_EMBED_ANNUAL' - name: 'privateIpEnabled' type: Boolean description: | diff --git a/mmv1/products/looker/product.yaml b/mmv1/products/looker/product.yaml index cf0fb3770f82..6a8eaef366ed 100644 --- a/mmv1/products/looker/product.yaml +++ b/mmv1/products/looker/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/managedkafka/Cluster.yaml b/mmv1/products/managedkafka/Cluster.yaml index 46d31473056d..aa3d7bbd5dca 100644 --- a/mmv1/products/managedkafka/Cluster.yaml +++ b/mmv1/products/managedkafka/Cluster.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'managedkafka_cluster_basic' diff --git a/mmv1/products/memcache/Instance.yaml b/mmv1/products/memcache/Instance.yaml index a654d8834a9a..8d7b62b7b0c8 100644 --- a/mmv1/products/memcache/Instance.yaml +++ b/mmv1/products/memcache/Instance.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'memcache_instance_basic' diff --git a/mmv1/products/memcache/product.yaml b/mmv1/products/memcache/product.yaml index d3735e947d86..61a78f7034a1 100644 --- a/mmv1/products/memcache/product.yaml +++ b/mmv1/products/memcache/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/memorystore/Instance.yaml b/mmv1/products/memorystore/Instance.yaml index 113e01ca5820..4d2d58368198 100644 --- a/mmv1/products/memorystore/Instance.yaml +++ b/mmv1/products/memorystore/Instance.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/memorystore_instance.go.tmpl' decoder: 'templates/terraform/decoders/memorystore_instance.go.tmpl' diff --git a/mmv1/products/metastore/Federation.yaml b/mmv1/products/metastore/Federation.yaml index 3ab688ab5fee..cba72d66e298 100644 --- a/mmv1/products/metastore/Federation.yaml +++ b/mmv1/products/metastore/Federation.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: exclude_import_test: true method_name_separator: ':' diff --git a/mmv1/products/metastore/Service.yaml b/mmv1/products/metastore/Service.yaml index 4b5367a38ee8..a380ce3120cd 100644 --- a/mmv1/products/metastore/Service.yaml +++ b/mmv1/products/metastore/Service.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'service_id' diff --git a/mmv1/products/migrationcenter/Group.yaml b/mmv1/products/migrationcenter/Group.yaml index c77ae4a0187d..fabad8b101ed 100644 --- a/mmv1/products/migrationcenter/Group.yaml +++ b/mmv1/products/migrationcenter/Group.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'migration_group_basic' diff --git a/mmv1/products/migrationcenter/PreferenceSet.yaml b/mmv1/products/migrationcenter/PreferenceSet.yaml index 8c62b83a24c8..705e70e123bb 100644 --- a/mmv1/products/migrationcenter/PreferenceSet.yaml +++ b/mmv1/products/migrationcenter/PreferenceSet.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'preference_set_basic' diff --git a/mmv1/products/mlengine/Model.yaml b/mmv1/products/mlengine/Model.yaml index b9958642c051..6b2b27e5f2d6 100644 --- a/mmv1/products/mlengine/Model.yaml +++ b/mmv1/products/mlengine/Model.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: schema_version: 1 state_upgraders: true diff --git a/mmv1/products/monitoring/AlertPolicy.yaml b/mmv1/products/monitoring/AlertPolicy.yaml index 24589944ca73..62e914c205f4 100644 --- a/mmv1/products/monitoring/AlertPolicy.yaml +++ b/mmv1/products/monitoring/AlertPolicy.yaml @@ -913,6 +913,17 @@ properties: This field is optional. If this field is not empty, then it must be a valid Prometheus label name. + - name: 'disableMetricValidation' + type: Boolean + description: | + Whether to disable metric existence validation for this condition. + + This allows alerting policies to be defined on metrics that do not yet + exist, improving advanced customer workflows such as configuring + alerting policies using Terraform. + + Users with the `monitoring.alertPolicyViewer` role are able to see the + name of the non-existent metric in the alerting policy condition. - name: 'notificationChannels' type: Array # TODO chrisst - turn this into a resource ref diff --git a/mmv1/products/netapp/ActiveDirectory.yaml b/mmv1/products/netapp/ActiveDirectory.yaml index 6db6cd7d5ec4..e1645256b002 100644 --- a/mmv1/products/netapp/ActiveDirectory.yaml +++ b/mmv1/products/netapp/ActiveDirectory.yaml @@ -149,7 +149,7 @@ properties: - name: 'kdcHostname' type: String description: | - Hostname of the Active Directory server used as Kerberos Key Distribution Center. Only requried for volumes using kerberized NFSv4.1 + Hostname of the Active Directory server used as Kerberos Key Distribution Center. Only required for volumes using kerberized NFSv4.1 required: false - name: 'kdcIp' type: String diff --git a/mmv1/products/netapp/Volume.yaml b/mmv1/products/netapp/Volume.yaml index 8a7a1bf1dc60..f47a34d81ebe 100644 --- a/mmv1/products/netapp/Volume.yaml +++ b/mmv1/products/netapp/Volume.yaml @@ -113,7 +113,7 @@ properties: - name: 'storagePool' type: String description: | - Name of the storage pool to create the volume in. Pool needs enough spare capacity to accomodate the volume. + Name of the storage pool to create the volume in. Pool needs enough spare capacity to accommodate the volume. required: true - name: 'network' type: String @@ -123,7 +123,7 @@ properties: - name: 'serviceLevel' type: String description: | - Service level of the volume. Inherited from storage pool. Supported values are : PREMIUM, EXTERME, STANDARD, FLEX. + Service level of the volume. Inherited from storage pool. Supported values are : PREMIUM, EXTREME, STANDARD, FLEX. output: true - name: 'capacityGib' type: String @@ -146,7 +146,7 @@ properties: - name: 'allowedClients' type: String description: |- - Defines the client ingress specification (allowed clients) as a comma seperated list with IPv4 CIDRs or IPv4 host addresses. + Defines the client ingress specification (allowed clients) as a comma separated list with IPv4 CIDRs or IPv4 host addresses. - name: 'hasRootAccess' type: String description: |- diff --git a/mmv1/products/netapp/VolumeReplication.yaml b/mmv1/products/netapp/VolumeReplication.yaml index 6f8f8bc0dfbc..0cdd7e2b899c 100644 --- a/mmv1/products/netapp/VolumeReplication.yaml +++ b/mmv1/products/netapp/VolumeReplication.yaml @@ -13,6 +13,7 @@ --- name: 'VolumeReplication' +api_resource_type_kind: Replication description: | Volume replication creates an asynchronous mirror of a volume in a different location. This capability lets you use the replicated volume for critical application activity in case of a location-wide outage diff --git a/mmv1/products/networkconnectivity/Group.yaml b/mmv1/products/networkconnectivity/Group.yaml index 00db44c3de50..7e52d56542eb 100644 --- a/mmv1/products/networkconnectivity/Group.yaml +++ b/mmv1/products/networkconnectivity/Group.yaml @@ -26,14 +26,7 @@ references: async: type: 'OpAsync' operation: - path: 'name' base_url: '{{op_id}}' - wait_ms: 1000 - result: - path: 'targetLink' - error: - path: 'error/errors' - message: 'message' # A handwritten sweeper is needed as the resource name can only be `default`, `center`, and `edge`. exclude_sweeper: true examples: diff --git a/mmv1/products/networkconnectivity/Hub.yaml b/mmv1/products/networkconnectivity/Hub.yaml index 8c9aa9bc663e..a5ce0ca1d634 100644 --- a/mmv1/products/networkconnectivity/Hub.yaml +++ b/mmv1/products/networkconnectivity/Hub.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: legacy_long_form_project: true examples: diff --git a/mmv1/products/networkconnectivity/InternalRange.yaml b/mmv1/products/networkconnectivity/InternalRange.yaml index 6b84faa36a5c..e49a78993362 100644 --- a/mmv1/products/networkconnectivity/InternalRange.yaml +++ b/mmv1/products/networkconnectivity/InternalRange.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_connectivity_internal_ranges_basic' diff --git a/mmv1/products/networkconnectivity/PolicyBasedRoute.yaml b/mmv1/products/networkconnectivity/PolicyBasedRoute.yaml index 01bab853dee5..2d80d2bd4e53 100644 --- a/mmv1/products/networkconnectivity/PolicyBasedRoute.yaml +++ b/mmv1/products/networkconnectivity/PolicyBasedRoute.yaml @@ -34,18 +34,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_connectivity_policy_based_route_basic' diff --git a/mmv1/products/networkconnectivity/RegionalEndpoint.yaml b/mmv1/products/networkconnectivity/RegionalEndpoint.yaml index 11a0a168f701..5e809e34fcf1 100644 --- a/mmv1/products/networkconnectivity/RegionalEndpoint.yaml +++ b/mmv1/products/networkconnectivity/RegionalEndpoint.yaml @@ -36,11 +36,7 @@ async: operation: base_url: '{{op_id}}' result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_connectivity_regional_endpoint_regional_access' diff --git a/mmv1/products/networkconnectivity/ServiceConnectionPolicy.yaml b/mmv1/products/networkconnectivity/ServiceConnectionPolicy.yaml index 38378dcae661..1ba54cabffbe 100644 --- a/mmv1/products/networkconnectivity/ServiceConnectionPolicy.yaml +++ b/mmv1/products/networkconnectivity/ServiceConnectionPolicy.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: update_encoder: 'templates/terraform/encoders/service_connection_policy.go.tmpl' examples: diff --git a/mmv1/products/networkconnectivity/Spoke.yaml b/mmv1/products/networkconnectivity/Spoke.yaml index f0e3df14e3d8..4ab3309a7845 100644 --- a/mmv1/products/networkconnectivity/Spoke.yaml +++ b/mmv1/products/networkconnectivity/Spoke.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: legacy_long_form_project: true examples: @@ -50,6 +44,12 @@ examples: network_name: 'net' hub_name: 'hub1' spoke_name: 'spoke1' + - name: 'network_connectivity_spoke_linked_vpc_network_group' + primary_resource_id: 'primary' + vars: + network_name: 'net-spoke' + hub_name: 'hub1-spoke' + spoke_name: 'group-spoke1' - name: 'network_connectivity_spoke_router_appliance_basic' primary_resource_id: 'primary' vars: @@ -128,15 +128,21 @@ properties: immutable: true resource: 'hub' imports: 'name' + - name: 'group' + type: String + description: The name of the group that this spoke is associated with. + immutable: true + default_from_api: true - name: 'linkedVpnTunnels' type: NestedObject description: The URIs of linked VPN tunnel resources - immutable: true conflicts: - linked_interconnect_attachments - linked_router_appliance_instances - linked_vpc_network - linked_producer_vpc_network + update_mask_fields: + - 'linkedVpnTunnels.includeImportRanges' properties: - name: 'uris' type: Array @@ -160,12 +166,13 @@ properties: - name: 'linkedInterconnectAttachments' type: NestedObject description: A collection of VLAN attachment resources. These resources should be redundant attachments that all advertise the same prefixes to Google Cloud. Alternatively, in active/passive configurations, all attachments should be capable of advertising the same prefixes. - immutable: true conflicts: - linked_vpn_tunnels - linked_router_appliance_instances - linked_vpc_network - linked_producer_vpc_network + update_mask_fields: + - 'linkedInterconnectAttachments.includeImportRanges' properties: - name: 'uris' type: Array @@ -189,12 +196,14 @@ properties: - name: 'linkedRouterApplianceInstances' type: NestedObject description: The URIs of linked Router appliance resources - immutable: true conflicts: - linked_interconnect_attachments - linked_vpn_tunnels - linked_vpc_network - linked_producer_vpc_network + update_mask_fields: + - 'linkedRouterApplianceInstances.instances' + - 'linkedRouterApplianceInstances.includeImportRanges' properties: - name: 'instances' type: Array @@ -209,11 +218,13 @@ properties: type: String description: The URI of the virtual machine resource immutable: true + required: true diff_suppress_func: 'tpgresource.CompareSelfLinkOrResourceName' - name: 'ipAddress' type: String description: The IP address on the VM to use for peering. immutable: true + required: true - name: 'siteToSiteDataTransfer' type: Boolean description: A value that controls whether site-to-site data transfer is enabled for these resources. Note that data transfer is available only in supported locations. diff --git a/mmv1/products/networkmanagement/ConnectivityTest.yaml b/mmv1/products/networkmanagement/ConnectivityTest.yaml index 6e92a73778ae..84286da4b688 100644 --- a/mmv1/products/networkmanagement/ConnectivityTest.yaml +++ b/mmv1/products/networkmanagement/ConnectivityTest.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: filename_override: 'connectivity_test_resource' examples: diff --git a/mmv1/products/networkmanagement/VpcFlowLogsConfig.yaml b/mmv1/products/networkmanagement/VpcFlowLogsConfig.yaml index 8267ed0d80b5..e0f438fb8f49 100644 --- a/mmv1/products/networkmanagement/VpcFlowLogsConfig.yaml +++ b/mmv1/products/networkmanagement/VpcFlowLogsConfig.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_management_vpc_flow_logs_config_interconnect_full' diff --git a/mmv1/products/networkmanagement/product.yaml b/mmv1/products/networkmanagement/product.yaml index b1c0dc0c06ea..1a1672445a6c 100644 --- a/mmv1/products/networkmanagement/product.yaml +++ b/mmv1/products/networkmanagement/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/networksecurity/AddressGroup.yaml b/mmv1/products/networksecurity/AddressGroup.yaml index e74732d4bfb7..e9269dcccc72 100644 --- a/mmv1/products/networksecurity/AddressGroup.yaml +++ b/mmv1/products/networksecurity/AddressGroup.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 20 update_minutes: 20 delete_minutes: 20 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: examples: diff --git a/mmv1/products/networksecurity/AuthorizationPolicy.yaml b/mmv1/products/networksecurity/AuthorizationPolicy.yaml index 54b4f6c5bc1b..3b71c4727279 100644 --- a/mmv1/products/networksecurity/AuthorizationPolicy.yaml +++ b/mmv1/products/networksecurity/AuthorizationPolicy.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_authorization_policy_basic' diff --git a/mmv1/products/networksecurity/AuthzPolicy.yaml b/mmv1/products/networksecurity/AuthzPolicy.yaml new file mode 100644 index 000000000000..9267467ba128 --- /dev/null +++ b/mmv1/products/networksecurity/AuthzPolicy.yaml @@ -0,0 +1,519 @@ +# Copyright 2024 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: 'AuthzPolicy' +description: | + AuthzPolicy is a resource that allows to forward traffic to a callout backend designed to scan the traffic for security purposes. +references: + guides: + api: 'https://cloud.google.com/load-balancing/docs/reference/network-security/rest/v1beta1/projects.locations.authzPolicies' +docs: +base_url: 'projects/{{project}}/locations/{{location}}/authzPolicies' +self_link: 'projects/{{project}}/locations/{{location}}/authzPolicies/{{name}}' +create_url: 'projects/{{project}}/locations/{{location}}/authzPolicies?authzPolicyId={{name}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/authzPolicies/{{name}}' + - '{{name}}' +timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 + result: + resource_inside_response: false +custom_code: +examples: + - name: 'network_services_authz_policy_advanced' + primary_resource_id: 'default' + vars: + resource_name: 'my-authz-policy' + network_name: 'lb-network' + subnet_name: 'backend-subnet' + proxy_subnet_name: 'proxy-only-subnet' + address_name: 'l7-ilb-ip-address' + health_check_name: 'l7-ilb-basic-check' + backend_url_name: 'l7-ilb-backend-service' + url_name: 'l7-ilb-map' + target_proxy_name: 'l7-ilb-proxy' + forwarding_rule_name: 'l7-ilb-forwarding-rule' + backend_authz_name: 'authz-service' + authz_extension_name: 'my-authz-ext' + test_env_vars: + project: 'PROJECT_NAME' +parameters: + - name: 'name' + type: String + description: | + Identifier. Name of the AuthzPolicy resource. + required: true + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' + custom_expand: 'templates/terraform/custom_expand/network_services_authz_policies.tmpl' + - name: 'location' + type: String + description: | + The location of the resource. + url_param_only: true + required: true +properties: + - name: 'createTime' + type: Time + description: | + The timestamp when the resource was created. + output: true + - name: 'updateTime' + type: Time + description: | + The timestamp when the resource was updated. + output: true + - name: 'description' + type: String + description: | + A human-readable description of the resource. + - name: 'labels' + type: KeyValueLabels + description: | + Set of labels associated with the AuthzExtension resource. + - name: 'target' + type: NestedObject + description: | + Specifies the set of resources to which this policy should be applied to. + required: true + properties: + - name: 'loadBalancingScheme' + type: Enum + description: | + All gateways and forwarding rules referenced by this policy and extensions must share the same load balancing scheme. + For more information, refer to [Backend services overview](https://cloud.google.com/load-balancing/docs/backend-service). + required: true + enum_values: + - 'INTERNAL_MANAGED' + - 'EXTERNAL_MANAGED' + - 'INTERNAL_SELF_MANAGED' + - name: 'resources' + type: Array + description: | + A list of references to the Forwarding Rules on which this policy will be applied. + diff_suppress_func: 'tpgresource.ProjectNumberDiffSuppress' + item_type: + type: String + - name: 'httpRules' + type: Array + description: | + A list of authorization HTTP rules to match against the incoming request.A policy match occurs when at least one HTTP rule matches the request or when no HTTP rules are specified in the policy. At least one HTTP Rule is required for Allow or Deny Action. + Limited to 5 rules. + item_type: + type: NestedObject + properties: + - name: 'from' + type: NestedObject + description: | + Describes properties of one or more sources of a request. + properties: + - name: 'sources' + type: Array + description: | + Describes the properties of a request's sources. At least one of sources or notSources must be specified. Limited to 5 sources. A match occurs when ANY source (in sources or notSources) matches the request. Within a single source, the match follows AND semantics across fields and OR semantics within a single field, i.e. a match occurs when ANY principal matches AND ANY ipBlocks match. + item_type: + type: NestedObject + properties: + - name: 'principals' + type: Array + description: | + A list of identities derived from the client's certificate. This field will not match on a request unless mutual TLS is enabled for the Forwarding rule or Gateway. Each identity is a string whose value is matched against the URI SAN, or DNS SAN or the subject field in the client's certificate. The match can be exact, prefix, suffix or a substring match. One of exact, prefix, suffix or contains must be specified. + Limited to 5 principals. + item_type: + type: NestedObject + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'resources' + type: Array + description: | + A list of resources to match against the resource of the source VM of a request. + Limited to 5 resources. + item_type: + type: NestedObject + properties: + - name: 'tagValueIdSet' + type: NestedObject + description: | + A list of resource tag value permanent IDs to match against the resource manager tags value associated with the source VM of a request. + properties: + - name: 'ids' + type: Array + description: | + A list of resource tag value permanent IDs to match against the resource manager tags value associated with the source VM of a request. The match follows AND semantics which means all the ids must match. + Limited to 5 matches. + item_type: + type: String + - name: 'iamServiceAccount' + type: NestedObject + description: | + An IAM service account to match against the source service account of the VM sending the request. + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'notSources' + type: Array + description: | + Describes the properties of a request's sources. At least one of sources or notSources must be specified. Limited to 5 sources. A match occurs when ANY source (in sources or notSources) matches the request. Within a single source, the match follows AND semantics across fields and OR semantics within a single field, i.e. a match occurs when ANY principal matches AND ANY ipBlocks match. + item_type: + type: NestedObject + properties: + - name: 'principals' + type: Array + description: | + A list of identities derived from the client's certificate. This field will not match on a request unless mutual TLS is enabled for the Forwarding rule or Gateway. Each identity is a string whose value is matched against the URI SAN, or DNS SAN or the subject field in the client's certificate. The match can be exact, prefix, suffix or a substring match. One of exact, prefix, suffix or contains must be specified. + Limited to 5 principals. + item_type: + type: NestedObject + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'resources' + type: Array + description: | + A list of resources to match against the resource of the source VM of a request. + Limited to 5 resources. + item_type: + type: NestedObject + properties: + - name: 'tagValueIdSet' + type: NestedObject + description: | + A list of resource tag value permanent IDs to match against the resource manager tags value associated with the source VM of a request. + properties: + - name: 'ids' + type: Array + description: | + A list of resource tag value permanent IDs to match against the resource manager tags value associated with the source VM of a request. The match follows AND semantics which means all the ids must match. + Limited to 5 matches. + item_type: + type: String + - name: 'iamServiceAccount' + type: NestedObject + description: | + An IAM service account to match against the source service account of the VM sending the request. + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'to' + type: NestedObject + description: | + Describes properties of one or more targets of a request + properties: + - name: 'operations' + type: Array + description: | + Describes properties of one or more targets of a request. At least one of operations or notOperations must be specified. Limited to 5 operations. A match occurs when ANY operation (in operations or notOperations) matches. Within an operation, the match follows AND semantics across fields and OR semantics within a field, i.e. a match occurs when ANY path matches AND ANY header matches and ANY method matches. + item_type: + type: NestedObject + properties: + - name: 'headerSet' + type: NestedObject + description: | + A list of headers to match against in http header. + properties: + - name: 'headers' + type: Array + description: | + A list of headers to match against in http header. The match can be one of exact, prefix, suffix, or contains (substring match). The match follows AND semantics which means all the headers must match. Matches are always case sensitive unless the ignoreCase is set. Limited to 5 matches. + item_type: + type: NestedObject + properties: + - name: 'name' + type: String + description: | + Specifies the name of the header in the request. + - name: 'value' + type: NestedObject + description: | + Specifies how the header match will be performed. + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'hosts' + type: Array + description: | + A list of HTTP Hosts to match against. The match can be one of exact, prefix, suffix, or contains (substring match). Matches are always case sensitive unless the ignoreCase is set. + Limited to 5 matches. + item_type: + type: NestedObject + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'paths' + type: Array + description: | + A list of paths to match against. The match can be one of exact, prefix, suffix, or contains (substring match). Matches are always case sensitive unless the ignoreCase is set. + Limited to 5 matches. + Note that this path match includes the query parameters. For gRPC services, this should be a fully-qualified name of the form /package.service/method. + item_type: + type: NestedObject + properties: + - name: 'ignoreCase' + type: Boolean + description: | + If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. For example, the matcher data will match both input string Data and data if set to true. + - name: 'exact' + type: String + description: | + The input string must match exactly the string specified here. + Examples: + * abc only matches the value abc. + - name: 'prefix' + type: String + description: | + The input string must have the prefix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value abc.xyz + - name: 'suffix' + type: String + description: | + The input string must have the suffix specified here. Note: empty prefix is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc + - name: 'contains' + type: String + description: | + The input string must have the substring specified here. Note: empty contains match is not allowed, please use regex instead. + Examples: + * abc matches the value xyz.abc.def + - name: 'methods' + type: Array + description: | + A list of HTTP methods to match against. Each entry must be a valid HTTP method name (GET, PUT, POST, HEAD, PATCH, DELETE, OPTIONS). It only allows exact match and is always case sensitive. + item_type: + type: String + - name: 'when' + type: String + description: | + CEL expression that describes the conditions to be satisfied for the action. The result of the CEL expression is ANDed with the from and to. Refer to the CEL language reference for a list of available attributes. + - name: 'action' + type: Enum + description: | + When the action is CUSTOM, customProvider must be specified. + When the action is ALLOW, only requests matching the policy will be allowed. + When the action is DENY, only requests matching the policy will be denied. + + When a request arrives, the policies are evaluated in the following order: + 1. If there is a CUSTOM policy that matches the request, the CUSTOM policy is evaluated using the custom authorization providers and the request is denied if the provider rejects the request. + 2. If there are any DENY policies that match the request, the request is denied. + 3. If there are no ALLOW policies for the resource or if any of the ALLOW policies match the request, the request is allowed. + 4. Else the request is denied by default if none of the configured AuthzPolicies with ALLOW action match the request. + required: true + enum_values: + - 'ALLOW' + - 'DENY' + - 'CUSTOM' + - name: 'customProvider' + type: NestedObject + description: | + Required if the action is CUSTOM. Allows delegating authorization decisions to Cloud IAP or to Service Extensions. One of cloudIap or authzExtension must be specified. + properties: + # Cloud IAP type has no fields according to the API + # https://cloud.google.com/load-balancing/docs/reference/network-security/rest/v1beta1/projects.locations.authzPolicies#cloudiap + - name: 'cloudIap' + type: NestedObject + description: | + Delegates authorization decisions to Cloud IAP. Applicable only for managed load balancers. Enabling Cloud IAP at the AuthzPolicy level is not compatible with Cloud IAP settings in the BackendService. Enabling IAP in both places will result in request failure. Ensure that IAP is enabled in either the AuthzPolicy or the BackendService but not in both places. + send_empty_value: true + custom_flatten: 'templates/terraform/custom_flatten/cloud_iap.tmpl' + custom_expand: 'templates/terraform/custom_expand/cloud_iap.tmpl' + properties: + - name: 'enabled' + type: Boolean + description: | + Enable Cloud IAP at the AuthzPolicy level. + required: true + - name: 'authzExtension' + type: NestedObject + description: | + Delegate authorization decision to user authored Service Extension. Only one of cloudIap or authzExtension can be specified. + properties: + - name: 'resources' + type: Array + description: | + A list of references to authorization extensions that will be invoked for requests matching this policy. Limited to 1 custom provider. + required: true + diff_suppress_func: 'tpgresource.ProjectNumberDiffSuppress' + item_type: + type: String diff --git a/mmv1/products/networksecurity/ClientTlsPolicy.yaml b/mmv1/products/networksecurity/ClientTlsPolicy.yaml index 8d2ab30215cf..22b8c9d6b41c 100644 --- a/mmv1/products/networksecurity/ClientTlsPolicy.yaml +++ b/mmv1/products/networksecurity/ClientTlsPolicy.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_client_tls_policy_basic' diff --git a/mmv1/products/networksecurity/GatewaySecurityPolicy.yaml b/mmv1/products/networksecurity/GatewaySecurityPolicy.yaml index 34cb3b04e40a..5675f2f0ad44 100644 --- a/mmv1/products/networksecurity/GatewaySecurityPolicy.yaml +++ b/mmv1/products/networksecurity/GatewaySecurityPolicy.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_gateway_security_policy_basic' diff --git a/mmv1/products/networksecurity/GatewaySecurityPolicyRule.yaml b/mmv1/products/networksecurity/GatewaySecurityPolicyRule.yaml index e3613d845375..126fc21bf333 100644 --- a/mmv1/products/networksecurity/GatewaySecurityPolicyRule.yaml +++ b/mmv1/products/networksecurity/GatewaySecurityPolicyRule.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_gateway_security_policy_rules_basic' diff --git a/mmv1/products/networksecurity/InterceptDeployment.yaml b/mmv1/products/networksecurity/InterceptDeployment.yaml new file mode 100644 index 000000000000..d65c33a43353 --- /dev/null +++ b/mmv1/products/networksecurity/InterceptDeployment.yaml @@ -0,0 +1,121 @@ +# Copyright 2024 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: 'InterceptDeployment' +description: InterceptDeployment represents the collectors within a Zone and is associated with a deployment group. +min_version: 'beta' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/interceptDeployments/{{intercept_deployment_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/interceptDeployments' +self_link: 'projects/{{project}}/locations/{{location}}/interceptDeployments/{{intercept_deployment_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/interceptDeployments?interceptDeploymentId={{intercept_deployment_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/interceptDeployments/{{intercept_deployment_id}}' +timeouts: + insert_minutes: 20 + update_minutes: 20 + delete_minutes: 20 +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + path: 'name' + wait_ms: 1000 + result: + path: 'response' + resource_inside_response: true + error: + path: 'error' + message: 'message' +custom_code: +examples: + - name: 'network_security_intercept_deployment_basic' + config_path: 'templates/terraform/examples/network_security_intercept_deployment_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + network_name: 'example-network' + subnetwork_name: 'example-subnet' + health_check_name: 'example-hc' + backend_service_name: 'example-bs' + forwarding_rule_name: 'example-fwr' + deployment_group_id: 'example-dg' + deployment_id: 'example-deployment' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/InterceptDeployment`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'interceptDeploymentId' + type: String + description: "Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nintercept_deployment_id from the method_signature of Create + RPC " + min_version: 'beta' + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Identifier. The name of the InterceptDeployment. ' + min_version: 'beta' + output: true + - name: 'createTime' + type: String + description: 'Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'forwardingRule' + type: String + description: "Immutable. The regional load balancer which the intercepted + traffic should be forwarded\nto. Format is:\nprojects/{project}/regions/{region}/forwardingRules/{forwardingRule} " + min_version: 'beta' + required: true + immutable: true + - name: 'interceptDeploymentGroup' + type: String + description: "Immutable. The Intercept Deployment Group that this resource + is part of. Format is:\n`projects/{project}/locations/global/interceptDeploymentGroups/{interceptDeploymentGroup}` " + min_version: 'beta' + required: true + immutable: true + - name: 'state' + type: String + description: "Current state of the deployment. \n Possible values:\n + STATE_UNSPECIFIED\nACTIVE\nCREATING\nDELETING\nOUT_OF_SYNC\nDELETE_FAILED" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/InterceptDeploymentGroup.yaml b/mmv1/products/networksecurity/InterceptDeploymentGroup.yaml new file mode 100644 index 000000000000..5ea32042f951 --- /dev/null +++ b/mmv1/products/networksecurity/InterceptDeploymentGroup.yaml @@ -0,0 +1,118 @@ +# Copyright 2024 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: 'InterceptDeploymentGroup' +description: A Deployment Group represents the collector deployments across different zones within an organization. +min_version: 'beta' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/interceptDeploymentGroups/{{intercept_deployment_group_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/interceptDeploymentGroups' +self_link: 'projects/{{project}}/locations/{{location}}/interceptDeploymentGroups/{{intercept_deployment_group_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/interceptDeploymentGroups?interceptDeploymentGroupId={{intercept_deployment_group_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/interceptDeploymentGroups/{{intercept_deployment_group_id}}' +timeouts: + insert_minutes: 20 + update_minutes: 20 + delete_minutes: 20 +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +custom_code: +examples: + - name: 'network_security_intercept_deployment_group_basic' + config_path: 'templates/terraform/examples/network_security_intercept_deployment_group_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + network_name: 'example-network' + subnetwork_name: 'example-subnet' + deployment_group_id: 'example-dg' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/InterceptDeploymentGroup`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'interceptDeploymentGroupId' + type: String + description: "Required. Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nintercept_deployment_group_id from the method_signature + of Create RPC " + min_version: 'beta' + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Output only. Identifier. Then name of the InterceptDeploymentGroup. ' + min_version: 'beta' + output: true + - name: 'createTime' + type: String + description: 'Output only. [Output only] Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Output only. [Output only] Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'network' + type: String + description: "Required. Immutable. The network that is being used for the deployment. + Format is:\nprojects/{project}/global/networks/{network}. " + min_version: 'beta' + required: true + immutable: true + - name: 'connectedEndpointGroups' + type: Array + min_version: 'beta' + description: 'Output only. The list of Intercept Endpoint Groups that are connected + to this resource. ' + output: true + item_type: + type: NestedObject + properties: + - name: 'name' + type: String + description: 'Output only. A connected intercept endpoint group. ' + min_version: 'beta' + output: true + - name: 'state' + type: String + description: "Output only. Current state of the deployment group. \n Possible values:\n + STATE_UNSPECIFIED\nACTIVE\nCREATING\nDELETING" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Output only. Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/MirroringDeployment.yaml b/mmv1/products/networksecurity/MirroringDeployment.yaml new file mode 100644 index 000000000000..e8d90168d6ac --- /dev/null +++ b/mmv1/products/networksecurity/MirroringDeployment.yaml @@ -0,0 +1,116 @@ +# Copyright 2024 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: 'MirroringDeployment' +description: MirroringDeployment represents the collectors within a Zone and is associated with a deployment group. +min_version: 'beta' +references: + guides: + 'Mirroring deployment overview': 'https://cloud.google.com/network-security-integration/docs/out-of-band/deployments-overview' + api: 'https://cloud.google.com/network-security-integration/docs/reference/rest/v1beta1/projects.locations.mirroringDeployments' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/mirroringDeployments/{{mirroring_deployment_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/mirroringDeployments' +self_link: 'projects/{{project}}/locations/{{location}}/mirroringDeployments/{{mirroring_deployment_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/mirroringDeployments?mirroringDeploymentId={{mirroring_deployment_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/mirroringDeployments/{{mirroring_deployment_id}}' +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +custom_code: +examples: + - name: 'network_security_mirroring_deployment_basic' + config_path: 'templates/terraform/examples/network_security_mirroring_deployment_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + network_name: 'example-network' + subnetwork_name: 'example-subnet' + health_check_name: 'example-hc' + backend_service_name: 'example-bs' + forwarding_rule_name: 'example-fwr' + deployment_group_id: 'example-dg' + deployment_id: 'example-deployment' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/MirroringDeployment`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'mirroringDeploymentId' + type: String + description: "Required. Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nmirroring_deployment_id from the method_signature of Create + RPC " + min_version: 'beta' + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Immutable. Identifier. The name of the MirroringDeployment. ' + min_version: 'beta' + immutable: true + output: true + - name: 'createTime' + type: String + description: 'Output only. [Output only] Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Output only. [Output only] Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'forwardingRule' + type: String + description: "Required. Immutable. The regional load balancer which the mirrored + traffic should be forwarded\nto. Format is:\nprojects/{project}/regions/{region}/forwardingRules/{forwardingRule} " + min_version: 'beta' + required: true + immutable: true + - name: 'mirroringDeploymentGroup' + type: String + description: "Required. Immutable. The Mirroring Deployment Group that this resource + is part of. Format is:\n`projects/{project}/locations/global/mirroringDeploymentGroups/{mirroringDeploymentGroup}` " + min_version: 'beta' + required: true + immutable: true + - name: 'state' + type: String + description: "Output only. Current state of the deployment. \n Possible values:\n + STATE_UNSPECIFIED\nACTIVE\nCREATING\nDELETING\nOUT_OF_SYNC\nDELETE_FAILED" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Output only. Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/MirroringDeploymentGroup.yaml b/mmv1/products/networksecurity/MirroringDeploymentGroup.yaml new file mode 100644 index 000000000000..f2dcfaffa10e --- /dev/null +++ b/mmv1/products/networksecurity/MirroringDeploymentGroup.yaml @@ -0,0 +1,119 @@ +# Copyright 2024 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: 'MirroringDeploymentGroup' +description: A Deployment Group represents the collector deployments across different zones within an organization. +min_version: 'beta' +references: + guides: + 'Mirroring deployment group overview': 'https://cloud.google.com/network-security-integration/docs/out-of-band/deployment-groups-overview' + api: 'https://cloud.google.com/network-security-integration/docs/reference/rest/v1beta1/projects.locations.mirroringDeploymentGroups' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/mirroringDeploymentGroups/{{mirroring_deployment_group_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/mirroringDeploymentGroups' +self_link: 'projects/{{project}}/locations/{{location}}/mirroringDeploymentGroups/{{mirroring_deployment_group_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/mirroringDeploymentGroups?mirroringDeploymentGroupId={{mirroring_deployment_group_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/mirroringDeploymentGroups/{{mirroring_deployment_group_id}}' +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +custom_code: +examples: + - name: 'network_security_mirroring_deployment_group_basic' + config_path: 'templates/terraform/examples/network_security_mirroring_deployment_group_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + network_name: 'example-network' + subnetwork_name: 'example-subnet' + deployment_group_id: 'example-dg' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/MirroringDeploymentGroup`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'mirroringDeploymentGroupId' + type: String + description: "Required. Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nmirroring_deployment_group_id from the method_signature + of Create RPC " + min_version: 'beta' + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Immutable. Identifier. Then name of the MirroringDeploymentGroup. ' + min_version: 'beta' + immutable: true + output: true + - name: 'createTime' + type: String + description: 'Output only. [Output only] Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Output only. [Output only] Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'network' + type: String + description: "Required. Immutable. The network that is being used for the deployment. + Format is:\nprojects/{project}/global/networks/{network}. " + min_version: 'beta' + required: true + immutable: true + - name: 'connectedEndpointGroups' + type: Array + description: 'Output only. The list of Mirroring Endpoint Groups that are connected + to this resource. ' + min_version: 'beta' + output: true + item_type: + type: NestedObject + properties: + - name: 'name' + type: String + description: 'Output only. A connected mirroring endpoint group. ' + min_version: 'beta' + output: true + - name: 'state' + type: String + description: "Output only. Current state of the deployment group. \n Possible values:\n + STATE_UNSPECIFIED\nACTIVE\nCREATING\nDELETING" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Output only. Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/MirroringEndpointGroup.yaml b/mmv1/products/networksecurity/MirroringEndpointGroup.yaml new file mode 100644 index 000000000000..5f77d9dc8dee --- /dev/null +++ b/mmv1/products/networksecurity/MirroringEndpointGroup.yaml @@ -0,0 +1,105 @@ +# Copyright 2024 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: 'MirroringEndpointGroup' +description: A mirroring endpoint group is a global resource in the consumer account representing the producer’s deployment group. +min_version: 'beta' +references: + guides: + 'Mirroring endpoint group overview': 'https://cloud.google.com/network-security-integration/docs/out-of-band/endpoint-groups-overview' + api: 'https://cloud.google.com/network-security-integration/docs/reference/rest/v1beta1/projects.locations.mirroringEndpointGroups' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroups/{{mirroring_endpoint_group_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroups' +self_link: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroups/{{mirroring_endpoint_group_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroups?mirroringEndpointGroupId={{mirroring_endpoint_group_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroups/{{mirroring_endpoint_group_id}}' +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +custom_code: +examples: + - name: 'network_security_mirroring_endpoint_group_basic' + config_path: 'templates/terraform/examples/network_security_mirroring_endpoint_group_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + network_name: 'example-network' + deployment_group_id: 'example-dg' + endpoint_group_id: 'example-eg' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/MirroringEndpointGroup`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'mirroringEndpointGroupId' + type: String + description: "Required. Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nmirroring_endpoint_group_id from the method_signature of + Create RPC " + min_version: 'beta' + url_param_only: true + required: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Immutable. Identifier. The name of the MirroringEndpointGroup. ' + min_version: 'beta' + immutable: true + output: true + - name: 'createTime' + type: String + description: 'Output only. [Output only] Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Output only. [Output only] Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'mirroringDeploymentGroup' + type: String + description: "Required. Immutable. The Mirroring Deployment Group that this resource + is connected to. Format\nis:\n`projects/{project}/locations/global/mirroringDeploymentGroups/{mirroringDeploymentGroup}` " + min_version: 'beta' + required: true + immutable: true + - name: 'state' + type: String + description: "Output only. Current state of the endpoint group. \n Possible values:\n + STATE_UNSPECIFIED\nACTIVE\nCLOSED\nCREATING\nDELETING\nOUT_OF_SYNC" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Output only. Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/MirroringEndpointGroupAssociation.yaml b/mmv1/products/networksecurity/MirroringEndpointGroupAssociation.yaml new file mode 100644 index 000000000000..3f4c4d3a4cc9 --- /dev/null +++ b/mmv1/products/networksecurity/MirroringEndpointGroupAssociation.yaml @@ -0,0 +1,132 @@ +# Copyright 2024 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: 'MirroringEndpointGroupAssociation' +description: Creates an association between a VPC and a mirroring endpoint group in order to mirror traffic in that VPC. +min_version: 'beta' +references: + guides: + 'Mirroring endpoint group association overview': 'https://cloud.google.com/network-security-integration/docs/out-of-band/endpoint-groups-overview#mirroring-endpoint-group-association' + api: 'https://cloud.google.com/network-security-integration/docs/reference/rest/v1beta1/projects.locations.mirroringEndpointGroupAssociations' +docs: +id_format: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroupAssociations/{{mirroring_endpoint_group_association_id}}' +base_url: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroupAssociations' +self_link: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroupAssociations/{{mirroring_endpoint_group_association_id}}' +create_url: 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroupAssociations?mirroringEndpointGroupAssociationId={{mirroring_endpoint_group_association_id}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/mirroringEndpointGroupAssociations/{{mirroring_endpoint_group_association_id}}' +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +custom_code: +examples: + - name: 'network_security_mirroring_endpoint_group_association_basic' + config_path: 'templates/terraform/examples/network_security_mirroring_endpoint_group_association_basic.tf.tmpl' + primary_resource_id: 'default' + vars: + producer_network_name: 'example-prod-network' + consumer_network_name: 'example-cons-network' + deployment_group_id: 'example-dg' + endpoint_group_id: 'example-eg' + endpoint_group_association_id: 'example-ega' +parameters: + - name: 'location' + type: String + description: 'Resource ID segment making up resource `name`. It identifies the resource + within its parent collection as described in https://google.aip.dev/122. See documentation + for resource type `networksecurity.googleapis.com/MirroringEndpointGroupAssociation`. ' + min_version: 'beta' + url_param_only: true + required: true + immutable: true + - name: 'mirroringEndpointGroupAssociationId' + type: String + description: "Optional. Id of the requesting object\nIf auto-generating Id server-side, + remove this field and\nmirroring_endpoint_group_association_id from the method_signature + of Create\nRPC " + min_version: 'beta' + url_param_only: true + immutable: true +properties: + - name: 'name' + type: String + description: 'Immutable. Identifier. The name of the MirroringEndpointGroupAssociation. ' + min_version: 'beta' + immutable: true + output: true + - name: 'createTime' + type: String + description: 'Output only. [Output only] Create time stamp ' + min_version: 'beta' + output: true + - name: 'updateTime' + type: String + description: 'Output only. [Output only] Update time stamp ' + min_version: 'beta' + output: true + - name: 'labels' + type: KeyValueLabels + description: 'Optional. Labels as key value pairs ' + min_version: 'beta' + - name: 'mirroringEndpointGroup' + type: String + description: "Required. Immutable. The Mirroring Endpoint Group that this resource + is connected to. Format\nis:\n`projects/{project}/locations/global/mirroringEndpointGroups/{mirroringEndpointGroup}` " + min_version: 'beta' + required: true + immutable: true + - name: 'network' + type: String + description: "Required. Immutable. The VPC network associated. Format:\nprojects/{project}/global/networks/{network}. " + min_version: 'beta' + required: true + immutable: true + - name: 'locationsDetails' + type: Array + description: 'Output only. The list of locations that this association is in and + its details. ' + min_version: 'beta' + output: true + item_type: + type: NestedObject + properties: + - name: 'location' + type: String + description: 'Output only. The cloud location. ' + min_version: 'beta' + output: true + - name: 'state' + type: String + description: "Output only. The association state in this location. \n + Possible values:\n STATE_UNSPECIFIED\nACTIVE\nOUT_OF_SYNC" + min_version: 'beta' + output: true + - name: 'state' + type: String + description: "Output only. Current state of the endpoint group association. \n + Possible values:\n STATE_UNSPECIFIED\nACTIVE\nCREATING\nDELETING\nCLOSED\nOUT_OF_SYNC\nDELETE_FAILED" + min_version: 'beta' + output: true + - name: 'reconciling' + type: Boolean + description: "Output only. Whether reconciling is in progress, recommended per\nhttps://google.aip.dev/128. " + min_version: 'beta' + output: true diff --git a/mmv1/products/networksecurity/ServerTlsPolicy.yaml b/mmv1/products/networksecurity/ServerTlsPolicy.yaml index ed91c2b05616..cd992c5e9dac 100644 --- a/mmv1/products/networksecurity/ServerTlsPolicy.yaml +++ b/mmv1/products/networksecurity/ServerTlsPolicy.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_server_tls_policy_basic' diff --git a/mmv1/products/networksecurity/TlsInspectionPolicy.yaml b/mmv1/products/networksecurity/TlsInspectionPolicy.yaml index 44488c080e1e..c43b6848c768 100644 --- a/mmv1/products/networksecurity/TlsInspectionPolicy.yaml +++ b/mmv1/products/networksecurity/TlsInspectionPolicy.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_tls_inspection_policy_basic' diff --git a/mmv1/products/networksecurity/UrlLists.yaml b/mmv1/products/networksecurity/UrlLists.yaml index bbf9e866040b..47c3c4a9adcf 100644 --- a/mmv1/products/networksecurity/UrlLists.yaml +++ b/mmv1/products/networksecurity/UrlLists.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_security_url_lists_basic' diff --git a/mmv1/products/networkservices/AuthzExtension.yaml b/mmv1/products/networkservices/AuthzExtension.yaml new file mode 100644 index 000000000000..3017001f2dfe --- /dev/null +++ b/mmv1/products/networkservices/AuthzExtension.yaml @@ -0,0 +1,147 @@ +# Copyright 2024 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: 'AuthzExtension' +description: | + AuthzExtension is a resource that allows traffic forwarding to a callout backend service to make an authorization decision. +references: + guides: + api: 'https://cloud.google.com/service-extensions/docs/reference/rest/v1beta1/projects.locations.authzExtensions' +docs: +base_url: 'projects/{{project}}/locations/{{location}}/authzExtensions' +self_link: 'projects/{{project}}/locations/{{location}}/authzExtensions/{{name}}' +create_url: 'projects/{{project}}/locations/{{location}}/authzExtensions?authzExtensionId={{name}}' +update_verb: 'PATCH' +update_mask: true +import_format: + - 'projects/{{project}}/locations/{{location}}/authzExtensions/{{name}}' + - '{{name}}' +timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 +autogen_async: true +async: + actions: ['create', 'delete', 'update'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + timeouts: + insert_minutes: 30 + update_minutes: 30 + delete_minutes: 30 + result: + resource_inside_response: false +custom_code: +examples: + - name: 'network_services_authz_extension_basic' + primary_resource_id: 'default' + vars: + resource_name: 'my-authz-ext' + backend_name: 'authz-service' + test_env_vars: + project: 'PROJECT_NAME' +parameters: + - name: 'name' + type: String + description: | + Identifier. Name of the AuthzExtension resource. + required: true + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' + custom_expand: 'templates/terraform/custom_expand/network_services_authz_extensions.tmpl' + - name: 'location' + type: String + description: | + The location of the resource. + url_param_only: true + required: true +properties: + - name: 'createTime' + type: Time + description: | + The timestamp when the resource was created. + output: true + - name: 'updateTime' + type: Time + description: | + The timestamp when the resource was updated. + output: true + - name: 'description' + type: String + description: | + A human-readable description of the resource. + - name: 'labels' + type: KeyValueLabels + description: | + Set of labels associated with the AuthzExtension resource. + - name: 'loadBalancingScheme' + type: Enum + description: | + All backend services and forwarding rules referenced by this extension must share the same load balancing scheme. + For more information, refer to [Backend services overview](https://cloud.google.com/load-balancing/docs/backend-service). + required: true + enum_values: + - 'INTERNAL_MANAGED' + - 'EXTERNAL_MANAGED' + - name: 'authority' + type: String + description: | + The :authority header in the gRPC request sent from Envoy to the extension service. + required: true + - name: 'service' + type: ResourceRef + description: | + The reference to the service that runs the extension. + To configure a callout extension, service must be a fully-qualified reference to a [backend service](https://cloud.google.com/compute/docs/reference/rest/v1/backendServices) in the format: + https://www.googleapis.com/compute/v1/projects/{project}/regions/{region}/backendServices/{backendService} or https://www.googleapis.com/compute/v1/projects/{project}/global/backendServices/{backendService}. + required: true + diff_suppress_func: 'tpgresource.ProjectNumberDiffSuppress' + resource: 'BackendService' + imports: 'selfLink' + - name: 'timeout' + type: String + description: | + Specifies the timeout for each individual message on the stream. The timeout must be between 10-10000 milliseconds. + required: true + diff_suppress_func: 'tpgresource.DurationDiffSuppress' + - name: 'failOpen' + type: Boolean + description: | + Determines how the proxy behaves if the call to the extension fails or times out. + When set to TRUE, request or response processing continues without error. Any subsequent extensions in the extension chain are also executed. When set to FALSE or the default setting of FALSE is used, one of the following happens: + * If response headers have not been delivered to the downstream client, a generic 500 error is returned to the client. The error response can be tailored by configuring a custom error response in the load balancer. + * If response headers have been delivered, then the HTTP stream to the downstream client is reset. + default_from_api: true + send_empty_value: true + - name: 'metadata' + type: KeyValuePairs + description: | + The metadata provided here is included as part of the metadata_context (of type google.protobuf.Struct) in the ProcessingRequest message sent to the extension server. The metadata is available under the namespace com.google.authz_extension.. The following variables are supported in the metadata Struct: + + {forwarding_rule_id} - substituted with the forwarding rule's fully qualified resource name. + - name: 'forwardHeaders' + type: Array + description: | + List of the HTTP headers to forward to the extension (from the client). If omitted, all headers are sent. Each element is a string indicating the header name. + item_type: + type: String + - name: 'wireFormat' + type: Enum + description: | + The format of communication supported by the callout extension. + default_value: "EXT_PROC_GRPC" + custom_flatten: 'templates/terraform/custom_flatten/default_if_empty.tmpl' + enum_values: + - 'WIRE_FORMAT_UNSPECIFIED' + - 'EXT_PROC_GRPC' diff --git a/mmv1/products/networkservices/EdgeCacheKeyset.yaml b/mmv1/products/networkservices/EdgeCacheKeyset.yaml index 6b1791387acb..ab01696322b3 100644 --- a/mmv1/products/networkservices/EdgeCacheKeyset.yaml +++ b/mmv1/products/networkservices/EdgeCacheKeyset.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 90 update_minutes: 90 delete_minutes: 90 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: error_abort_predicates: diff --git a/mmv1/products/networkservices/EdgeCacheOrigin.yaml b/mmv1/products/networkservices/EdgeCacheOrigin.yaml index 9795fd35960b..8fbb43ddcbd0 100644 --- a/mmv1/products/networkservices/EdgeCacheOrigin.yaml +++ b/mmv1/products/networkservices/EdgeCacheOrigin.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 120 update_minutes: 120 delete_minutes: 120 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_edge_cache_origin_basic' diff --git a/mmv1/products/networkservices/EdgeCacheService.yaml b/mmv1/products/networkservices/EdgeCacheService.yaml index 8dc29e7098a5..01a55cd39a83 100644 --- a/mmv1/products/networkservices/EdgeCacheService.yaml +++ b/mmv1/products/networkservices/EdgeCacheService.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_edge_cache_service_basic' diff --git a/mmv1/products/networkservices/EndpointPolicy.yaml b/mmv1/products/networkservices/EndpointPolicy.yaml index e9a4a5c8e2ec..31a63ddf4f00 100644 --- a/mmv1/products/networkservices/EndpointPolicy.yaml +++ b/mmv1/products/networkservices/EndpointPolicy.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_endpoint_policy_basic' diff --git a/mmv1/products/networkservices/Gateway.yaml b/mmv1/products/networkservices/Gateway.yaml index d68da1c01f5d..20b788a5cebf 100644 --- a/mmv1/products/networkservices/Gateway.yaml +++ b/mmv1/products/networkservices/Gateway.yaml @@ -39,18 +39,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/network_services_gateway.go.tmpl' post_delete: 'templates/terraform/post_delete/network_services_gateway.go.tmpl' diff --git a/mmv1/products/networkservices/GrpcRoute.yaml b/mmv1/products/networkservices/GrpcRoute.yaml index 9b20be0c1cd1..4f1351409a31 100644 --- a/mmv1/products/networkservices/GrpcRoute.yaml +++ b/mmv1/products/networkservices/GrpcRoute.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_grpc_route_basic' diff --git a/mmv1/products/networkservices/HttpRoute.yaml b/mmv1/products/networkservices/HttpRoute.yaml index 6bdf81f12ec1..63251e3d01b5 100644 --- a/mmv1/products/networkservices/HttpRoute.yaml +++ b/mmv1/products/networkservices/HttpRoute.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_http_route_basic' diff --git a/mmv1/products/networkservices/Mesh.yaml b/mmv1/products/networkservices/Mesh.yaml index 80f4146d6052..a065b5d3227e 100644 --- a/mmv1/products/networkservices/Mesh.yaml +++ b/mmv1/products/networkservices/Mesh.yaml @@ -39,18 +39,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_mesh_basic' diff --git a/mmv1/products/networkservices/ServiceBinding.yaml b/mmv1/products/networkservices/ServiceBinding.yaml index cd11c4b6be2e..47c3b1190cba 100644 --- a/mmv1/products/networkservices/ServiceBinding.yaml +++ b/mmv1/products/networkservices/ServiceBinding.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 10 update_minutes: 10 delete_minutes: 10 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: schema_version: 1 state_upgraders: true diff --git a/mmv1/products/networkservices/ServiceLbPolicies.yaml b/mmv1/products/networkservices/ServiceLbPolicies.yaml index dd57f5520bb2..79d4dd45cb97 100644 --- a/mmv1/products/networkservices/ServiceLbPolicies.yaml +++ b/mmv1/products/networkservices/ServiceLbPolicies.yaml @@ -39,18 +39,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_service_lb_policies_basic' diff --git a/mmv1/products/networkservices/TcpRoute.yaml b/mmv1/products/networkservices/TcpRoute.yaml index 077bde0ebfeb..68bca50121ca 100644 --- a/mmv1/products/networkservices/TcpRoute.yaml +++ b/mmv1/products/networkservices/TcpRoute.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_tcp_route_basic' diff --git a/mmv1/products/networkservices/TlsRoute.yaml b/mmv1/products/networkservices/TlsRoute.yaml index 7f5a27d6a09d..56b53a50eeb1 100644 --- a/mmv1/products/networkservices/TlsRoute.yaml +++ b/mmv1/products/networkservices/TlsRoute.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'network_services_tls_route_basic' diff --git a/mmv1/products/notebooks/Environment.yaml b/mmv1/products/notebooks/Environment.yaml index 9c528fa43f5e..937e76426616 100644 --- a/mmv1/products/notebooks/Environment.yaml +++ b/mmv1/products/notebooks/Environment.yaml @@ -32,14 +32,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'notebook_environment_basic' diff --git a/mmv1/products/notebooks/Instance.yaml b/mmv1/products/notebooks/Instance.yaml index ac10bf97af41..1f4d6426311c 100644 --- a/mmv1/products/notebooks/Instance.yaml +++ b/mmv1/products/notebooks/Instance.yaml @@ -39,14 +39,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'instance_name' diff --git a/mmv1/products/notebooks/Location.yaml b/mmv1/products/notebooks/Location.yaml index 4a9bdcb551e4..30575d5645fb 100644 --- a/mmv1/products/notebooks/Location.yaml +++ b/mmv1/products/notebooks/Location.yaml @@ -28,14 +28,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' collection_url_key: 'items' custom_code: parameters: diff --git a/mmv1/products/notebooks/Runtime.yaml b/mmv1/products/notebooks/Runtime.yaml index 7003246adfbf..4d73e00b2ff6 100644 --- a/mmv1/products/notebooks/Runtime.yaml +++ b/mmv1/products/notebooks/Runtime.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'runtime_name' diff --git a/mmv1/products/notebooks/product.yaml b/mmv1/products/notebooks/product.yaml index 3adbcacc9380..74551e208fa6 100644 --- a/mmv1/products/notebooks/product.yaml +++ b/mmv1/products/notebooks/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/oracledatabase/AutonomousDatabase.yaml b/mmv1/products/oracledatabase/AutonomousDatabase.yaml index a29e404a3bb7..efac72d3178f 100644 --- a/mmv1/products/oracledatabase/AutonomousDatabase.yaml +++ b/mmv1/products/oracledatabase/AutonomousDatabase.yaml @@ -35,36 +35,50 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 240 update_minutes: 120 delete_minutes: 120 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: + pre_delete: 'templates/terraform/pre_delete/oracledatabase_autonomous_database.go.tmpl' examples: - name: 'oracledatabase_autonomous_database_basic' primary_resource_id: 'myADB' vars: project: 'my-project' autonomous_database_id: 'my-instance' + database_name: 'mydatabase' + deletion_protection: 'true' + ignore_read_extra: + - 'deletion_protection' test_vars_overrides: - 'project': '"oci-terraform-testing"' - 'autonomous_database_id': '"my-adb-instance-id"' + deletion_protection: 'false' + project: '"oci-terraform-testing"' + database_name: 'fmt.Sprintf("tftestdatabase%s", acctest.RandString(t, 10))' - name: 'oracledatabase_autonomous_database_full' primary_resource_id: 'myADB' vars: project: 'my-project' autonomous_database_id: 'my-instance' + database_name: 'mydatabase' + endpoint_name: 'myendpoint' + deletion_protection: 'true' + ignore_read_extra: + - 'deletion_protection' test_vars_overrides: - 'project': '"oci-terraform-testing"' - 'autonomous_database_id': '"my-adb-instance-id-2"' + project: '"oci-terraform-testing"' + deletion_protection: 'false' + database_name: 'fmt.Sprintf("tftestdatabase%s", acctest.RandString(t, 10))' + endpoint_name: 'fmt.Sprintf("tftestendpoint%s", acctest.RandString(t, 10))' +virtual_fields: + - name: 'deletion_protection' + type: Boolean + default_value: true + description: 'Whether or not to allow Terraform to destroy the instance. + Unless this field is set to false in Terraform state, a terraform destroy + or terraform apply that would delete the instance will fail.' parameters: - name: 'location' type: String diff --git a/mmv1/products/oracledatabase/CloudExadataInfrastructure.yaml b/mmv1/products/oracledatabase/CloudExadataInfrastructure.yaml index 981e026aa0f7..85591aa84c1b 100644 --- a/mmv1/products/oracledatabase/CloudExadataInfrastructure.yaml +++ b/mmv1/products/oracledatabase/CloudExadataInfrastructure.yaml @@ -35,36 +35,54 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 240 update_minutes: 120 delete_minutes: 120 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: + pre_delete: 'templates/terraform/pre_delete/oracledatabase_cloud_exadata_infrastructure.go.tmpl' examples: - name: 'oracledatabase_cloud_exadata_infrastructure_basic' primary_resource_id: 'my-cloud-exadata' vars: project: 'my-project' cloud_exadata_infrastructure_id: 'my-instance' + deletion_protection: 'true' + ignore_read_extra: + - 'deletion_protection' test_vars_overrides: 'project': '"oci-terraform-testing"' - 'cloud_exadata_infrastructure_id': '"ofake-exadata-basic"' + 'deletion_protection': 'false' + # ofake- prefix is needed to create a dummy resource for testing purposes only + # See: https://github.com/hashicorp/terraform-provider-google/issues/19983#issuecomment-2516403770 + # As a result these resources are not sweepable + # See: https://github.com/hashicorp/terraform-provider-google/issues/20599 + cloud_exadata_infrastructure_id: 'fmt.Sprintf("ofake-tf-test-exadata-basic-%s", acctest.RandString(t, 10))' - name: 'oracledatabase_cloud_exadata_infrastructure_full' primary_resource_id: 'my-cloud-exadata' vars: project: 'my-project' cloud_exadata_infrastructure_id: 'my-instance' + deletion_protection: 'true' + ignore_read_extra: + - 'deletion_protection' test_vars_overrides: 'project': '"oci-terraform-testing"' - 'cloud_exadata_infrastructure_id': '"ofake-exadata-full"' + 'deletion_protection': 'false' + # ofake- prefix is needed to create a dummy resource for testing purposes only + # See: https://github.com/hashicorp/terraform-provider-google/issues/19983#issuecomment-2516403770 + # As a result these resources are not sweepable + # See: https://github.com/hashicorp/terraform-provider-google/issues/20599 + cloud_exadata_infrastructure_id: 'fmt.Sprintf("ofake-tf-test-exadata-full-%s", acctest.RandString(t, 10))' +virtual_fields: + - name: 'deletion_protection' + type: Boolean + default_value: true + description: 'Whether or not to allow Terraform to destroy the instance. + Unless this field is set to false in Terraform state, a terraform destroy + or terraform apply that would delete the instance will fail.' parameters: - name: 'location' type: String diff --git a/mmv1/products/oracledatabase/CloudVmCluster.yaml b/mmv1/products/oracledatabase/CloudVmCluster.yaml index e61c3e55295c..17bf222d0e87 100644 --- a/mmv1/products/oracledatabase/CloudVmCluster.yaml +++ b/mmv1/products/oracledatabase/CloudVmCluster.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 120 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_delete: 'templates/terraform/pre_delete/oracledatabase_cloud_vmcluster.go.tmpl' examples: @@ -64,8 +58,12 @@ examples: test_vars_overrides: 'deletion_protection': 'false' 'project': '"oci-terraform-testing"' - 'cloud_vm_cluster_id': '"ofake-vmcluster-basic"' - 'cloud_exadata_infrastructure_id': '"ofake-exadata-for-vm-basic"' + # ofake- prefix is needed to create a dummy resource for testing purposes only + # See: https://github.com/hashicorp/terraform-provider-google/issues/19983#issuecomment-2516403770 + # As a result these resources are not sweepable + # See: https://github.com/hashicorp/terraform-provider-google/issues/20599 + cloud_vm_cluster_id: 'fmt.Sprintf("ofake-tf-test-vmcluster-basic-%s", acctest.RandString(t, 10))' + cloud_exadata_infrastructure_id: 'fmt.Sprintf("ofake-tf-test-exadata-for-vmcluster-basic-%s", acctest.RandString(t, 10))' - name: 'oracledatabase_cloud_vmcluster_full' primary_resource_id: 'my_vmcluster' vars: @@ -78,15 +76,19 @@ examples: test_vars_overrides: 'deletion_protection': 'false' 'project': '"oci-terraform-testing"' - 'cloud_vm_cluster_id': '"ofake-vmcluster-full"' - 'cloud_exadata_infrastructure_id': '"ofake-exadata-for-vm-full"' + # ofake- prefix is needed to create a dummy resource for testing purposes only + # See: https://github.com/hashicorp/terraform-provider-google/issues/19983#issuecomment-2516403770 + # As a result these resources are not sweepable + # See: https://github.com/hashicorp/terraform-provider-google/issues/20599 + cloud_vm_cluster_id: 'fmt.Sprintf("ofake-tf-test-vmcluster-full-%s", acctest.RandString(t, 10))' + cloud_exadata_infrastructure_id: 'fmt.Sprintf("ofake-tf-test-exadata-for-vmcluster-full-%s", acctest.RandString(t, 10))' virtual_fields: - name: 'deletion_protection' type: Boolean default_value: true - description: 'Whether or not to allow Terraform to destroy the instance. - Unless this field is set to false in Terraform state, a terraform destroy - or terraform apply that would delete the instance will fail.' + description: 'Whether Terraform will be prevented from destroying the cluster. + Deleting this cluster via terraform destroy or terraform apply will only + succeed if this field is false in the Terraform state.' parameters: - name: 'location' type: String diff --git a/mmv1/products/orgpolicy/Policy.yaml b/mmv1/products/orgpolicy/Policy.yaml index 6a5260d3efa6..05abe2dff0b2 100644 --- a/mmv1/products/orgpolicy/Policy.yaml +++ b/mmv1/products/orgpolicy/Policy.yaml @@ -54,6 +54,9 @@ examples: - name: 'org_policy_policy_dry_run_spec' primary_resource_id: 'primary' exclude_test: true + - name: 'org_policy_policy_parameters_enforce' + primary_resource_id: 'primary' + exclude_test: true parameters: - name: 'parent' type: String @@ -121,6 +124,13 @@ properties: send_empty_value: true custom_flatten: 'templates/terraform/custom_flatten/enum_bool.go.tmpl' custom_expand: 'templates/terraform/custom_expand/enum_bool.go.tmpl' + - name: 'parameters' + description: 'Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }' + custom_flatten: 'templates/terraform/custom_flatten/json_schema.tmpl' + custom_expand: 'templates/terraform/custom_expand/json_schema.tmpl' + state_func: 'func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }' + validation: + function: 'validation.StringIsJSON' - name: 'condition' type: NestedObject description: 'A condition which determines whether this rule is used in the evaluation of the policy. When set, the `expression` field in the `Expr'' must include from 1 to 10 subexpressions, joined by the "||" or "&&" operators. Each subexpression must be of the form "resource.matchTag(''/tag_key_short_name, ''tag_value_short_name'')". or "resource.matchTagId(''tagKeys/key_id'', ''tagValues/value_id'')". where key_name and value_name are the resource names for Label Keys and Values. These names are available from the Tag Manager Service. An example expression is: "resource.matchTag(''123456789/environment, ''prod'')". or "resource.matchTagId(''tagKeys/123'', ''tagValues/456'')".' @@ -197,6 +207,13 @@ properties: send_empty_value: true custom_flatten: 'templates/terraform/custom_flatten/enum_bool.go.tmpl' custom_expand: 'templates/terraform/custom_expand/enum_bool.go.tmpl' + - name: 'parameters' + description: 'Optional. Required for Managed Constraints if parameters defined in constraints. Pass parameter values when policy enforcement is enabled. Ensure that parameter value types match those defined in the constraint definition. For example: { \"allowedLocations\" : [\"us-east1\", \"us-west1\"], \"allowAll\" : true }' + custom_flatten: 'templates/terraform/custom_flatten/json_schema.tmpl' + custom_expand: 'templates/terraform/custom_expand/json_schema.tmpl' + state_func: 'func(v interface{}) string { s, _ := structure.NormalizeJsonString(v); return s }' + validation: + function: 'validation.StringIsJSON' - name: 'condition' type: NestedObject description: 'A condition which determines whether this rule is used in the evaluation of the policy. When set, the `expression` field in the `Expr'' must include from 1 to 10 subexpressions, joined by the "||" or "&&" operators. Each subexpression must be of the form "resource.matchTag(''/tag_key_short_name, ''tag_value_short_name'')". or "resource.matchTagId(''tagKeys/key_id'', ''tagValues/value_id'')". where key_name and value_name are the resource names for Label Keys and Values. These names are available from the Tag Manager Service. An example expression is: "resource.matchTag(''123456789/environment, ''prod'')". or "resource.matchTagId(''tagKeys/123'', ''tagValues/456'')".' diff --git a/mmv1/products/parallelstore/Instance.yaml b/mmv1/products/parallelstore/Instance.yaml index 77e8e46fabe6..7fd33f0f00af 100644 --- a/mmv1/products/parallelstore/Instance.yaml +++ b/mmv1/products/parallelstore/Instance.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'parallelstore_instance_basic' diff --git a/mmv1/products/privateca/CaPool.yaml b/mmv1/products/privateca/CaPool.yaml index bf9eb535475d..67d719aac79a 100644 --- a/mmv1/products/privateca/CaPool.yaml +++ b/mmv1/products/privateca/CaPool.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' allowed_iam_role: 'roles/privateca.certificateManager' diff --git a/mmv1/products/privateca/Certificate.yaml b/mmv1/products/privateca/Certificate.yaml index 3f3bc0331225..47a64dda8fdd 100644 --- a/mmv1/products/privateca/Certificate.yaml +++ b/mmv1/products/privateca/Certificate.yaml @@ -1111,7 +1111,7 @@ properties: properties: - name: 'keyId' type: String - description: The value of the KeyId in lowercase hexidecimal. + description: The value of the KeyId in lowercase hexadecimal. immutable: true - name: 'publicKey' type: NestedObject diff --git a/mmv1/products/privateca/CertificateAuthority.yaml b/mmv1/products/privateca/CertificateAuthority.yaml index 138790090552..e0f585d01e89 100644 --- a/mmv1/products/privateca/CertificateAuthority.yaml +++ b/mmv1/products/privateca/CertificateAuthority.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/privateca_certificate_authority.go.tmpl' decoder: 'templates/terraform/decoders/treat_deleted_state_as_gone.go.tmpl' @@ -225,7 +219,7 @@ properties: properties: - name: 'keyId' type: String - description: The value of the KeyId in lowercase hexidecimal. + description: The value of the KeyId in lowercase hexadecimal. immutable: true - name: 'x509Config' type: NestedObject diff --git a/mmv1/products/privateca/CertificateTemplate.yaml b/mmv1/products/privateca/CertificateTemplate.yaml index 0ba347554c68..2f440e386815 100644 --- a/mmv1/products/privateca/CertificateTemplate.yaml +++ b/mmv1/products/privateca/CertificateTemplate.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' allowed_iam_role: 'roles/privateca.templateUser' diff --git a/mmv1/products/privilegedaccessmanager/Entitlement.yaml b/mmv1/products/privilegedaccessmanager/Entitlement.yaml index 735489009c36..f0256cc04075 100644 --- a/mmv1/products/privilegedaccessmanager/Entitlement.yaml +++ b/mmv1/products/privilegedaccessmanager/Entitlement.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/privileged_access_manager_entitlement.go.tmpl' pre_update: 'templates/terraform/pre_update/privileged_access_manager_entitlement.go.tmpl' diff --git a/mmv1/products/privilegedaccessmanager/product.yaml b/mmv1/products/privilegedaccessmanager/product.yaml index 7fce6b404c13..80f3598d8bae 100644 --- a/mmv1/products/privilegedaccessmanager/product.yaml +++ b/mmv1/products/privilegedaccessmanager/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/redis/Cluster.yaml b/mmv1/products/redis/Cluster.yaml index 6888932eca07..9a841e1ee0cf 100644 --- a/mmv1/products/redis/Cluster.yaml +++ b/mmv1/products/redis/Cluster.yaml @@ -462,7 +462,7 @@ properties: description: | Optional. Available fsync modes. - - NO - Do not explicilty call fsync(). Rely on OS defaults. + - NO - Do not explicitly call fsync(). Rely on OS defaults. - EVERYSEC - Call fsync() once per second in a background thread. A balance between performance and durability. - ALWAYS - Call fsync() for earch write command. enum_values: diff --git a/mmv1/products/redis/Instance.yaml b/mmv1/products/redis/Instance.yaml index 8eff54a1863c..419ae6c60bb7 100644 --- a/mmv1/products/redis/Instance.yaml +++ b/mmv1/products/redis/Instance.yaml @@ -20,6 +20,8 @@ references: 'Official Documentation': 'https://cloud.google.com/memorystore/docs/redis/' api: 'https://cloud.google.com/memorystore/docs/redis/reference/rest/v1/projects.locations.instances' docs: + attributes: | + * `auth_string` - AUTH String set on the instance. This field will only be populated if auth_enabled is true. base_url: 'projects/{{project}}/locations/{{region}}/instances' create_url: 'projects/{{project}}/locations/{{region}}/instances?instanceId={{name}}' update_verb: 'PATCH' diff --git a/mmv1/products/securesourcemanager/BranchRule.yaml b/mmv1/products/securesourcemanager/BranchRule.yaml index 5d5bd25580f9..d2e9cb0aec64 100644 --- a/mmv1/products/securesourcemanager/BranchRule.yaml +++ b/mmv1/products/securesourcemanager/BranchRule.yaml @@ -36,13 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'secure_source_manager_branch_rule_basic' diff --git a/mmv1/products/securesourcemanager/Instance.yaml b/mmv1/products/securesourcemanager/Instance.yaml index 3681f7765c1c..f5f2efc865fa 100644 --- a/mmv1/products/securesourcemanager/Instance.yaml +++ b/mmv1/products/securesourcemanager/Instance.yaml @@ -36,18 +36,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' allowed_iam_role: 'roles/securesourcemanager.instanceManager' diff --git a/mmv1/products/securesourcemanager/Repository.yaml b/mmv1/products/securesourcemanager/Repository.yaml index 4e695d6e71b2..1957d651ff85 100644 --- a/mmv1/products/securesourcemanager/Repository.yaml +++ b/mmv1/products/securesourcemanager/Repository.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' allowed_iam_role: 'roles/securesourcemanager.repoAdmin' diff --git a/mmv1/products/serviceusage/ConsumerQuotaOverride.yaml b/mmv1/products/serviceusage/ConsumerQuotaOverride.yaml index fd0fa90342b3..e8a2789c608f 100644 --- a/mmv1/products/serviceusage/ConsumerQuotaOverride.yaml +++ b/mmv1/products/serviceusage/ConsumerQuotaOverride.yaml @@ -43,14 +43,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' identity: - name nested_query: diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index 6185b2db1561..f7b1dffc0cb7 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -47,14 +47,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/spanner_database.go.tmpl' encoder: 'templates/terraform/encoders/spanner_database.go.tmpl' diff --git a/mmv1/products/spanner/Instance.yaml b/mmv1/products/spanner/Instance.yaml index bfaada78f130..3e1263b14dfc 100644 --- a/mmv1/products/spanner/Instance.yaml +++ b/mmv1/products/spanner/Instance.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/spanner_instance.go.tmpl' encoder: 'templates/terraform/encoders/spanner_instance.go.tmpl' diff --git a/mmv1/products/sql/Database.yaml b/mmv1/products/sql/Database.yaml index 089cb3384f0c..e523d433662f 100644 --- a/mmv1/products/sql/Database.yaml +++ b/mmv1/products/sql/Database.yaml @@ -36,15 +36,8 @@ async: type: 'OpAsync' operation: base_url: 'projects/{{project}}/operations/{{op_id}}' - kind: 'sql#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' collection_url_key: 'items' custom_code: pre_delete: 'templates/terraform/pre_delete/sql_database_deletion_policy.tmpl' diff --git a/mmv1/products/sql/SourceRepresentationInstance.yaml b/mmv1/products/sql/SourceRepresentationInstance.yaml index dff9a0c49b71..98cd2f038f32 100644 --- a/mmv1/products/sql/SourceRepresentationInstance.yaml +++ b/mmv1/products/sql/SourceRepresentationInstance.yaml @@ -33,15 +33,8 @@ async: type: 'OpAsync' operation: base_url: 'projects/{{project}}/operations/{{op_id}}' - kind: 'sql#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/sql_source_representation_instance.go.tmpl' decoder: 'templates/terraform/decoders/sql_source_representation_instance.go.tmpl' diff --git a/mmv1/products/sql/product.yaml b/mmv1/products/sql/product.yaml index c01f03e7c6f1..17d4e589c162 100644 --- a/mmv1/products/sql/product.yaml +++ b/mmv1/products/sql/product.yaml @@ -24,12 +24,5 @@ async: type: "OpAsync" operation: base_url: 'projects/{{project}}/operations/{{op_id}}' - kind: 'sql#operation' - path: 'name' - wait_ms: 1000 result: - path: 'targetLink' resource_inside_response: false - error: - path: 'error/errors' - message: 'message' diff --git a/mmv1/products/tags/TagBinding.yaml b/mmv1/products/tags/TagBinding.yaml index 7d378c7b81b0..b1a7e709e36e 100644 --- a/mmv1/products/tags/TagBinding.yaml +++ b/mmv1/products/tags/TagBinding.yaml @@ -41,14 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' nested_query: keys: - tagBindings diff --git a/mmv1/products/tags/TagKey.yaml b/mmv1/products/tags/TagKey.yaml index 9391e856684b..094ff285112c 100644 --- a/mmv1/products/tags/TagKey.yaml +++ b/mmv1/products/tags/TagKey.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' diff --git a/mmv1/products/tags/TagValue.yaml b/mmv1/products/tags/TagValue.yaml index fd9d9c38ac41..932f3d4ad65e 100644 --- a/mmv1/products/tags/TagValue.yaml +++ b/mmv1/products/tags/TagValue.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' diff --git a/mmv1/products/tags/product.yaml b/mmv1/products/tags/product.yaml index 465ee0b0cc16..4e87e685af12 100644 --- a/mmv1/products/tags/product.yaml +++ b/mmv1/products/tags/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/tpu/Node.yaml b/mmv1/products/tpu/Node.yaml index d3271e15c5d3..a61d4a11e210 100644 --- a/mmv1/products/tpu/Node.yaml +++ b/mmv1/products/tpu/Node.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/tpu_node.tmpl' custom_diff: diff --git a/mmv1/products/tpu/product.yaml b/mmv1/products/tpu/product.yaml index 3df3220eb0d6..a9302af0cd89 100644 --- a/mmv1/products/tpu/product.yaml +++ b/mmv1/products/tpu/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/tpuv2/QueuedResource.yaml b/mmv1/products/tpuv2/QueuedResource.yaml new file mode 100644 index 000000000000..4e409e6baedd --- /dev/null +++ b/mmv1/products/tpuv2/QueuedResource.yaml @@ -0,0 +1,97 @@ +# Copyright 2024 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: 'QueuedResource' +description: | + A Cloud TPU Queued Resource. +min_version: 'beta' +references: + guides: + 'Official Documentation': 'https://cloud.google.com/tpu/docs/' + api: 'https://cloud.google.com/tpu/docs/reference/rest/v2/projects.locations.queuedResources' +base_url: 'projects/{{project}}/locations/{{zone}}/queuedResources' +self_link: 'projects/{{project}}/locations/{{zone}}/queuedResources/{{name}}' +create_url: 'projects/{{project}}/locations/{{zone}}/queuedResources?queuedResourceId={{name}}' +immutable: true +autogen_async: true +async: + actions: ['create', 'delete'] + type: 'OpAsync' + operation: + base_url: '{{op_id}}' + result: + resource_inside_response: true +examples: + - name: 'tpu_v2_queued_resource_basic' + primary_resource_id: 'qr' + min_version: 'beta' + vars: + qr_name: 'test-qr' + tpu_name: 'test-tpu' + test_env_vars: + project: 'PROJECT_NAME' + skip_vcr: true +parameters: + - name: 'zone' + type: String + description: | + The GCP location for the Queued Resource. If it is not provided, the provider zone is used. + url_param_only: true + immutable: true + default_from_api: true +properties: + - name: 'name' + type: String + description: | + The immutable name of the Queued Resource. + required: true + immutable: true + custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.tmpl' + - name: 'tpu' + type: NestedObject + description: | + Defines a TPU resource. + properties: + - name: 'nodeSpec' + type: Array + description: | + The TPU node(s) being requested. + item_type: + type: NestedObject + properties: + - name: 'parent' + description: | + The parent resource name. + required: true + diff_suppress_func: 'tpgresource.ProjectNumberDiffSuppress' + - name: 'nodeId' + description: | + Unqualified node identifier used to identify the node in the project once provisioned. + - name: 'node' + type: NestedObject + description: | + The node. + required: true + properties: + - name: 'runtimeVersion' + required: true + description: | + Runtime version for the TPU. + - name: 'acceleratorType' + default_from_api: true + description: | + TPU accelerator type for the TPU. If not specified, this defaults to 'v2-8'. + - name: 'description' + description: | + Text description of the TPU. diff --git a/mmv1/products/tpuv2/Vm.yaml b/mmv1/products/tpuv2/Vm.yaml index a88502ec6eeb..983769860327 100644 --- a/mmv1/products/tpuv2/Vm.yaml +++ b/mmv1/products/tpuv2/Vm.yaml @@ -38,14 +38,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/tpu_vm.go.tmpl' custom_diff: @@ -127,14 +121,14 @@ properties: min_version: 'beta' immutable: true default_from_api: true + conflicts: + - network_configs properties: - name: 'network' type: String description: | The name of the network for the TPU node. It must be a preexisting Google Compute Engine - network. If both network and subnetwork are specified, the given subnetwork must belong - to the given network. If network is not specified, it will be looked up from the - subnetwork if one is provided, or otherwise use "default". + network. If none is provided, "default" will be used. min_version: 'beta' immutable: true default_from_api: true @@ -142,9 +136,7 @@ properties: type: String description: | The name of the subnetwork for the TPU node. It must be a preexisting Google Compute - Engine subnetwork. If both network and subnetwork are specified, the given subnetwork - must belong to the given network. If subnetwork is not specified, the subnetwork with the - same name as the network will be used. + Engine subnetwork. If none is provided, "default" will be used. min_version: 'beta' immutable: true default_from_api: true @@ -164,6 +156,64 @@ properties: min_version: 'beta' immutable: true send_empty_value: true + - name: 'queueCount' + type: Integer + description: | + Specifies networking queue count for TPU VM instance's network interface. + required: false + min_version: 'beta' + immutable: true + - name: 'networkConfigs' + type: Array + description: | + Repeated network configurations for the TPU node. This field is used to specify multiple + network configs for the TPU node. + min_version: 'beta' + immutable: true + conflicts: + - network_config + item_type: + type: NestedObject + properties: + - name: 'network' + type: String + description: | + The name of the network for the TPU node. It must be a preexisting Google Compute Engine + network. If none is provided, "default" will be used. + min_version: 'beta' + immutable: true + default_from_api: true + - name: 'subnetwork' + type: String + description: | + The name of the subnetwork for the TPU node. It must be a preexisting Google Compute + Engine subnetwork. If none is provided, "default" will be used. + min_version: 'beta' + immutable: true + default_from_api: true + - name: 'enableExternalIps' + type: Boolean + description: | + Indicates that external IP addresses would be associated with the TPU workers. If set to + false, the specified subnetwork or network should have Private Google Access enabled. + min_version: 'beta' + immutable: true + send_empty_value: true + - name: 'canIpForward' + type: Boolean + description: | + Allows the TPU node to send and receive packets with non-matching destination or source + IPs. This is required if you plan to use the TPU workers to forward routes. + min_version: 'beta' + immutable: true + send_empty_value: true + - name: 'queueCount' + type: Integer + description: | + Specifies networking queue count for TPU VM instance's network interface. + required: false + min_version: 'beta' + immutable: true - name: 'serviceAccount' type: NestedObject description: | diff --git a/mmv1/products/vertexai/Dataset.yaml b/mmv1/products/vertexai/Dataset.yaml index 446cb4f9a86b..ab7a10f564cb 100644 --- a/mmv1/products/vertexai/Dataset.yaml +++ b/mmv1/products/vertexai/Dataset.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_dataset' diff --git a/mmv1/products/vertexai/DeploymentResourcePool.yaml b/mmv1/products/vertexai/DeploymentResourcePool.yaml index 7ddf3cf2ecce..980b90f7be77 100644 --- a/mmv1/products/vertexai/DeploymentResourcePool.yaml +++ b/mmv1/products/vertexai/DeploymentResourcePool.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/wrap_object_with_deployment_resource_pool_id.go.tmpl' examples: diff --git a/mmv1/products/vertexai/Endpoint.yaml b/mmv1/products/vertexai/Endpoint.yaml index 4a6bc362f498..4a8f25b7174f 100644 --- a/mmv1/products/vertexai/Endpoint.yaml +++ b/mmv1/products/vertexai/Endpoint.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' diff --git a/mmv1/products/vertexai/FeatureGroup.yaml b/mmv1/products/vertexai/FeatureGroup.yaml index 10f692c6f15e..33af2984901d 100644 --- a/mmv1/products/vertexai/FeatureGroup.yaml +++ b/mmv1/products/vertexai/FeatureGroup.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_feature_group' diff --git a/mmv1/products/vertexai/FeatureGroupFeature.yaml b/mmv1/products/vertexai/FeatureGroupFeature.yaml index a542a4ca32d8..c3ef98901eba 100644 --- a/mmv1/products/vertexai/FeatureGroupFeature.yaml +++ b/mmv1/products/vertexai/FeatureGroupFeature.yaml @@ -36,14 +36,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_feature_group_feature' diff --git a/mmv1/products/vertexai/FeatureOnlineStore.yaml b/mmv1/products/vertexai/FeatureOnlineStore.yaml index d268b3140de2..76abeb31e7f8 100644 --- a/mmv1/products/vertexai/FeatureOnlineStore.yaml +++ b/mmv1/products/vertexai/FeatureOnlineStore.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: pre_delete: 'templates/terraform/pre_delete/vertex_ai_force_delete.go.tmpl' examples: diff --git a/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml b/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml index 597e4b8bd594..28a291c1ade2 100644 --- a/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml +++ b/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_featureonlinestore_featureview' diff --git a/mmv1/products/vertexai/Featurestore.yaml b/mmv1/products/vertexai/Featurestore.yaml index 7a86385bf345..65bd0c72dc5c 100644 --- a/mmv1/products/vertexai/Featurestore.yaml +++ b/mmv1/products/vertexai/Featurestore.yaml @@ -34,14 +34,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' fetch_iam_policy_verb: 'POST' diff --git a/mmv1/products/vertexai/FeaturestoreEntitytype.yaml b/mmv1/products/vertexai/FeaturestoreEntitytype.yaml index c847f218e6a4..d54677cb7850 100644 --- a/mmv1/products/vertexai/FeaturestoreEntitytype.yaml +++ b/mmv1/products/vertexai/FeaturestoreEntitytype.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' include_project: true iam_policy: method_name_separator: ':' diff --git a/mmv1/products/vertexai/FeaturestoreEntitytypeFeature.yaml b/mmv1/products/vertexai/FeaturestoreEntitytypeFeature.yaml index 788faa5d127d..9ee2d60374af 100644 --- a/mmv1/products/vertexai/FeaturestoreEntitytypeFeature.yaml +++ b/mmv1/products/vertexai/FeaturestoreEntitytypeFeature.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' include_project: true custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/vertex_ai_featurestore_entitytype_feature.go.tmpl' diff --git a/mmv1/products/vertexai/Index.yaml b/mmv1/products/vertexai/Index.yaml index 03156c7dc9bc..373c163e1e04 100644 --- a/mmv1/products/vertexai/Index.yaml +++ b/mmv1/products/vertexai/Index.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_update: 'templates/terraform/custom_update/vertex_ai_index.go.tmpl' examples: diff --git a/mmv1/products/vertexai/IndexEndpoint.yaml b/mmv1/products/vertexai/IndexEndpoint.yaml index aa41d873d3fa..2359963086b9 100644 --- a/mmv1/products/vertexai/IndexEndpoint.yaml +++ b/mmv1/products/vertexai/IndexEndpoint.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_index_endpoint' diff --git a/mmv1/products/vertexai/IndexEndpointDeployedIndex.yaml b/mmv1/products/vertexai/IndexEndpointDeployedIndex.yaml index 719d6ed862e7..e2f4f9306576 100644 --- a/mmv1/products/vertexai/IndexEndpointDeployedIndex.yaml +++ b/mmv1/products/vertexai/IndexEndpointDeployedIndex.yaml @@ -39,18 +39,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 45 update_minutes: 45 delete_minutes: 20 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' include_project: true custom_code: encoder: 'templates/terraform/encoders/vertex_ai_index_endpoint_deployed_index.go.tmpl' @@ -187,7 +181,7 @@ properties: description: | A description of resources that the DeployedIndex uses, which to large degree are decided by Vertex AI, and optionally allows only a modest additional configuration. - # Note: Having the fields within automaticResouces not being marked as immutable was done in order to support the ability to update such fields. See : https://github.com/GoogleCloudPlatform/magic-modules/pull/11039#issuecomment-2209316648 + # Note: Having the fields within automaticResources not being marked as immutable was done in order to support the ability to update such fields. See : https://github.com/GoogleCloudPlatform/magic-modules/pull/11039#issuecomment-2209316648 default_from_api: true properties: - name: 'minReplicaCount' diff --git a/mmv1/products/vertexai/MetadataStore.yaml b/mmv1/products/vertexai/MetadataStore.yaml index 6eb75f5ee9cc..3a04ea22c1e8 100644 --- a/mmv1/products/vertexai/MetadataStore.yaml +++ b/mmv1/products/vertexai/MetadataStore.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 40 update_minutes: 20 delete_minutes: 20 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vertex_ai_metadata_store' diff --git a/mmv1/products/vertexai/Tensorboard.yaml b/mmv1/products/vertexai/Tensorboard.yaml index c5f3aeac0853..348aa70934cf 100644 --- a/mmv1/products/vertexai/Tensorboard.yaml +++ b/mmv1/products/vertexai/Tensorboard.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: custom_import: 'templates/terraform/custom_import/vertex_ai_tensorboard_import.go.tmpl' examples: diff --git a/mmv1/products/vmwareengine/Cluster.yaml b/mmv1/products/vmwareengine/Cluster.yaml index 9222c8560759..c0747647c637 100644 --- a/mmv1/products/vmwareengine/Cluster.yaml +++ b/mmv1/products/vmwareengine/Cluster.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 5000 timeouts: insert_minutes: 210 update_minutes: 190 delete_minutes: 150 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: # There is a handwritten sweeper that provides a list of locations to sweep diff --git a/mmv1/products/vmwareengine/ExternalAccessRule.yaml b/mmv1/products/vmwareengine/ExternalAccessRule.yaml index 2a138a9033d8..0e7ca5990d8e 100644 --- a/mmv1/products/vmwareengine/ExternalAccessRule.yaml +++ b/mmv1/products/vmwareengine/ExternalAccessRule.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: # There is a handwritten sweeper that provides a list of locations to sweep diff --git a/mmv1/products/vmwareengine/ExternalAddress.yaml b/mmv1/products/vmwareengine/ExternalAddress.yaml index 0ee682155163..d7680f5aeaf3 100644 --- a/mmv1/products/vmwareengine/ExternalAddress.yaml +++ b/mmv1/products/vmwareengine/ExternalAddress.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 40 update_minutes: 20 delete_minutes: 20 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: # There is a handwritten sweeper that provides a list of locations to sweep diff --git a/mmv1/products/vmwareengine/Network.yaml b/mmv1/products/vmwareengine/Network.yaml index 45a9b8c22696..2de29c7af869 100644 --- a/mmv1/products/vmwareengine/Network.yaml +++ b/mmv1/products/vmwareengine/Network.yaml @@ -37,14 +37,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: # There is a handwritten sweeper that provides a list of locations to sweep exclude_sweeper: true diff --git a/mmv1/products/vmwareengine/NetworkPeering.yaml b/mmv1/products/vmwareengine/NetworkPeering.yaml index 4fa566d6ec1d..97bd86253660 100644 --- a/mmv1/products/vmwareengine/NetworkPeering.yaml +++ b/mmv1/products/vmwareengine/NetworkPeering.yaml @@ -35,14 +35,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vmware_engine_network_peering_ven' diff --git a/mmv1/products/vmwareengine/NetworkPolicy.yaml b/mmv1/products/vmwareengine/NetworkPolicy.yaml index 06478ef3a760..3e9ed4011aa8 100644 --- a/mmv1/products/vmwareengine/NetworkPolicy.yaml +++ b/mmv1/products/vmwareengine/NetworkPolicy.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 5000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'vmware_engine_network_policy_basic' diff --git a/mmv1/products/vmwareengine/PrivateCloud.yaml b/mmv1/products/vmwareengine/PrivateCloud.yaml index 151e3641c458..c5a48a4dd396 100644 --- a/mmv1/products/vmwareengine/PrivateCloud.yaml +++ b/mmv1/products/vmwareengine/PrivateCloud.yaml @@ -35,18 +35,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 5000 timeouts: insert_minutes: 240 update_minutes: 190 delete_minutes: 150 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: constants: 'templates/terraform/constants/vmwareengine_private_cloud.go.tmpl' update_encoder: 'templates/terraform/update_encoder/private_cloud.go.tmpl' diff --git a/mmv1/products/vmwareengine/Subnet.yaml b/mmv1/products/vmwareengine/Subnet.yaml index 90ea9e00ca15..5603709a4436 100644 --- a/mmv1/products/vmwareengine/Subnet.yaml +++ b/mmv1/products/vmwareengine/Subnet.yaml @@ -41,14 +41,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' include_project: true custom_code: examples: diff --git a/mmv1/products/vpcaccess/Connector.yaml b/mmv1/products/vpcaccess/Connector.yaml index f57e663f9f32..7a881c119d53 100644 --- a/mmv1/products/vpcaccess/Connector.yaml +++ b/mmv1/products/vpcaccess/Connector.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: encoder: 'templates/terraform/encoders/no_send_name.go.tmpl' decoder: 'templates/terraform/decoders/long_name_to_self_link.go.tmpl' diff --git a/mmv1/products/workbench/Instance.yaml b/mmv1/products/workbench/Instance.yaml index 846936c4235e..94d727e1e0e9 100644 --- a/mmv1/products/workbench/Instance.yaml +++ b/mmv1/products/workbench/Instance.yaml @@ -33,14 +33,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'name' diff --git a/mmv1/products/workbench/product.yaml b/mmv1/products/workbench/product.yaml index f676ed876949..f453551ea553 100644 --- a/mmv1/products/workbench/product.yaml +++ b/mmv1/products/workbench/product.yaml @@ -23,11 +23,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/workflows/Workflow.yaml b/mmv1/products/workflows/Workflow.yaml index a26587490204..0bb75a3642ed 100644 --- a/mmv1/products/workflows/Workflow.yaml +++ b/mmv1/products/workflows/Workflow.yaml @@ -40,14 +40,8 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' custom_code: extra_schema_entry: 'templates/terraform/extra_schema_entry/workflow.tmpl' encoder: 'templates/terraform/encoders/workflow.go.tmpl' diff --git a/mmv1/products/workflows/product.yaml b/mmv1/products/workflows/product.yaml index ed6e2f3aaad6..db966f5dd565 100644 --- a/mmv1/products/workflows/product.yaml +++ b/mmv1/products/workflows/product.yaml @@ -25,11 +25,5 @@ async: type: "OpAsync" operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 result: - path: 'response' resource_inside_response: true - error: - path: 'error' - message: 'message' diff --git a/mmv1/products/workstations/Workstation.yaml b/mmv1/products/workstations/Workstation.yaml index ed5a1bac7173..6480c9ffdd0d 100644 --- a/mmv1/products/workstations/Workstation.yaml +++ b/mmv1/products/workstations/Workstation.yaml @@ -38,18 +38,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'workstation_id' diff --git a/mmv1/products/workstations/WorkstationCluster.yaml b/mmv1/products/workstations/WorkstationCluster.yaml index 2f46fc926fb7..9141425f275d 100644 --- a/mmv1/products/workstations/WorkstationCluster.yaml +++ b/mmv1/products/workstations/WorkstationCluster.yaml @@ -37,18 +37,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 60 update_minutes: 60 delete_minutes: 60 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' custom_code: examples: - name: 'workstation_cluster_basic' diff --git a/mmv1/products/workstations/WorkstationConfig.yaml b/mmv1/products/workstations/WorkstationConfig.yaml index f871da5d0967..9ccd463add55 100644 --- a/mmv1/products/workstations/WorkstationConfig.yaml +++ b/mmv1/products/workstations/WorkstationConfig.yaml @@ -40,18 +40,12 @@ async: type: 'OpAsync' operation: base_url: '{{op_id}}' - path: 'name' - wait_ms: 1000 timeouts: insert_minutes: 30 update_minutes: 30 delete_minutes: 30 result: - path: 'response' resource_inside_response: false - error: - path: 'error' - message: 'message' iam_policy: method_name_separator: ':' parent_resource_attribute: 'workstation_config_id' diff --git a/mmv1/provider/terraform.go b/mmv1/provider/terraform.go index 0820c16caac2..056a1ffeb893 100644 --- a/mmv1/provider/terraform.go +++ b/mmv1/provider/terraform.go @@ -313,7 +313,7 @@ func (t Terraform) getCommonCopyFiles(versionName string, generateCode, generate // save the folder name to foldersCopiedToGoogleDir var foldersCopiedToGoogleDir []string if generateCode { - foldersCopiedToGoogleDir = []string{"third_party/terraform/services", "third_party/terraform/acctest", "third_party/terraform/sweeper", "third_party/terraform/provider", "third_party/terraform/tpgdclresource", "third_party/terraform/tpgiamresource", "third_party/terraform/tpgresource", "third_party/terraform/transport", "third_party/terraform/fwmodels", "third_party/terraform/fwprovider", "third_party/terraform/fwtransport", "third_party/terraform/fwresource", "third_party/terraform/verify", "third_party/terraform/envvar", "third_party/terraform/functions", "third_party/terraform/test-fixtures"} + foldersCopiedToGoogleDir = []string{"third_party/terraform/services", "third_party/terraform/acctest", "third_party/terraform/sweeper", "third_party/terraform/provider", "third_party/terraform/tpgdclresource", "third_party/terraform/tpgiamresource", "third_party/terraform/tpgresource", "third_party/terraform/transport", "third_party/terraform/fwmodels", "third_party/terraform/fwprovider", "third_party/terraform/fwtransport", "third_party/terraform/fwresource", "third_party/terraform/fwutils", "third_party/terraform/fwvalidators", "third_party/terraform/verify", "third_party/terraform/envvar", "third_party/terraform/functions", "third_party/terraform/test-fixtures"} } googleDir := "google" if versionName != "ga" { diff --git a/mmv1/provider/terraform/common~copy.yaml b/mmv1/provider/terraform/common~copy.yaml index b9ad0c850979..1784bffb4170 100644 --- a/mmv1/provider/terraform/common~copy.yaml +++ b/mmv1/provider/terraform/common~copy.yaml @@ -101,6 +101,20 @@ '<%= dir -%>/fwprovider/<%= fname -%>': 'third_party/terraform/fwprovider/<%= fname -%>' <% end -%> +<% + Dir["third_party/terraform/fwutils/*.go"].each do |file_path| + fname = file_path.split('/')[-1] +-%> +'<%= dir -%>/fwutils/<%= fname -%>': 'third_party/terraform/fwutils/<%= fname -%>' +<% end -%> + +<% + Dir["third_party/terraform/fwvalidators/*.go"].each do |file_path| + fname = file_path.split('/')[-1] +-%> +'<%= dir -%>/fwvalidators/<%= fname -%>': 'third_party/terraform/fwvalidators/<%= fname -%>' +<% end -%> + <% Dir["third_party/terraform/fwtransport/*.go"].each do |file_path| fname = file_path.split('/')[-1] diff --git a/mmv1/provider/terraform_tgc_v6.go b/mmv1/provider/terraform_tgc_v6.go new file mode 100644 index 000000000000..2a577190fd27 --- /dev/null +++ b/mmv1/provider/terraform_tgc_v6.go @@ -0,0 +1,150 @@ +// Copyright 2024 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. + +// Code generator for a library converting terraform state to gcp objects. + +package provider + +import ( + "bytes" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/GoogleCloudPlatform/magic-modules/mmv1/api" + "github.com/GoogleCloudPlatform/magic-modules/mmv1/api/product" + "github.com/otiai10/copy" +) + +// This proivder is for both tfplan2cai and cai2hcl conversions, +// and copying other files, such as transport.go +type TerraformGoogleConversionV6 struct { + TargetVersionName string + + Version product.Version + + Product *api.Product + + StartTime time.Time +} + +func NewTerraformGoogleConversionV6(product *api.Product, versionName string, startTime time.Time) TerraformGoogleConversionV6 { + t := TerraformGoogleConversionV6{ + Product: product, + TargetVersionName: versionName, + Version: *product.VersionObjOrClosest(versionName), + StartTime: startTime, + } + + t.Product.SetPropertiesBasedOnVersion(&t.Version) + for _, r := range t.Product.Objects { + r.SetCompiler(ProviderName(t)) + r.ImportPath = ImportPathFromVersion(versionName) + } + + return t +} + +func (tgc TerraformGoogleConversionV6) Generate(outputFolder, productPath, resourceToGenerate string, generateCode, generateDocs bool) { + tgc.GenerateTfToCaiObjects(outputFolder, resourceToGenerate, generateCode, generateDocs) + tgc.GenerateCaiToHclObjects(outputFolder, resourceToGenerate, generateCode, generateDocs) +} + +func (tgc TerraformGoogleConversionV6) GenerateTfToCaiObjects(outputFolder, resourceToGenerate string, generateCode, generateDocs bool) { +} + +func (tgc TerraformGoogleConversionV6) GenerateCaiToHclObjects(outputFolder, resourceToGenerate string, generateCode, generateDocs bool) { +} + +func (tgc TerraformGoogleConversionV6) CompileCommonFiles(outputFolder string, products []*api.Product, overridePath string) { + tgc.CompileTfToCaiCommonFiles(outputFolder, products) + tgc.CompileCaiToHclCommonFiles(outputFolder, products) +} + +func (tgc TerraformGoogleConversionV6) CompileTfToCaiCommonFiles(outputFolder string, products []*api.Product) { + log.Printf("Compiling common files for tgc v6 tfplan2cai.") + + resourceConverters := map[string]string{ + "tfplan2cai/converters/resource_converters.go": "templates/tgc_v6/tfplan2cai/resource_converters.go.tmpl", + } + templateData := NewTemplateData(outputFolder, tgc.TargetVersionName) + tgc.CompileFileList(outputFolder, resourceConverters, *templateData, products) +} + +func (tgc TerraformGoogleConversionV6) CompileCaiToHclCommonFiles(outputFolder string, products []*api.Product) { + log.Printf("Compiling common files for tgc v6 tfplan2cai.") + + resourceConverters := map[string]string{ + "cai2hcl/converters/resource_converters.go": "templates/tgc_v6/cai2hcl/resource_converters.go.tmpl", + } + templateData := NewTemplateData(outputFolder, tgc.TargetVersionName) + tgc.CompileFileList(outputFolder, resourceConverters, *templateData, products) +} + +func (tgc TerraformGoogleConversionV6) CompileFileList(outputFolder string, files map[string]string, fileTemplate TemplateData, products []*api.Product) { + if err := os.MkdirAll(outputFolder, os.ModePerm); err != nil { + log.Println(fmt.Errorf("error creating output directory %v: %v", outputFolder, err)) + } + + for target, source := range files { + targetFile := filepath.Join(outputFolder, target) + targetDir := filepath.Dir(targetFile) + if err := os.MkdirAll(targetDir, os.ModePerm); err != nil { + log.Println(fmt.Errorf("error creating output directory %v: %v", targetDir, err)) + } + + templates := []string{ + source, + } + + formatFile := filepath.Ext(targetFile) == ".go" + + fileTemplate.GenerateFile(targetFile, source, tgc, formatFile, templates...) + tgc.replaceImportPath(outputFolder, target) + } +} + +func (tgc TerraformGoogleConversionV6) CopyCommonFiles(outputFolder string, generateCode, generateDocs bool) { + if !generateCode { + return + } + + log.Printf("Copying common files for tgc v6.") + + if err := os.MkdirAll(outputFolder, os.ModePerm); err != nil { + log.Println(fmt.Errorf("error creating output directory %v: %v", outputFolder, err)) + } + + if err := copy.Copy("third_party/tgc_v6", outputFolder); err != nil { + log.Println(fmt.Errorf("error copying directory %v: %v", outputFolder, err)) + } +} + +func (tgc TerraformGoogleConversionV6) replaceImportPath(outputFolder, target string) { + // Replace import paths to reference the resources dir instead of the google provider + targetFile := filepath.Join(outputFolder, target) + sourceByte, err := os.ReadFile(targetFile) + if err != nil { + log.Fatalf("Cannot read file %s to replace import path: %s", targetFile, err) + } + + // replace google to google-beta + gaImportPath := ImportPathFromVersion("ga") + sourceByte = bytes.Replace(sourceByte, []byte(gaImportPath), []byte(TERRAFORM_PROVIDER_BETA+"/"+RESOURCE_DIRECTORY_BETA), -1) + err = os.WriteFile(targetFile, sourceByte, 0644) + if err != nil { + log.Fatalf("Cannot write file %s to replace import path: %s", target, err) + } +} diff --git a/mmv1/templates/terraform/constants/access_context_manager.go.tmpl b/mmv1/templates/terraform/constants/access_context_manager.go.tmpl index 6d999edf1ebb..bbde0e0968e7 100644 --- a/mmv1/templates/terraform/constants/access_context_manager.go.tmpl +++ b/mmv1/templates/terraform/constants/access_context_manager.go.tmpl @@ -1,4 +1,4 @@ -func {{$.ResourceName}}EgressToResourcesDiffSupressFunc(_, _, _ string, d *schema.ResourceData) bool { +func {{$.ResourceName}}EgressToResourcesDiffSuppressFunc(_, _, _ string, d *schema.ResourceData) bool { old, new := d.GetChange("egress_to.0.resources") oldResources, err := tpgresource.InterfaceSliceToStringSlice(old) @@ -19,7 +19,7 @@ func {{$.ResourceName}}EgressToResourcesDiffSupressFunc(_, _, _ string, d *schem return slices.Equal(oldResources, newResources) } -func {{$.ResourceName}}IngressToResourcesDiffSupressFunc(_, _, _ string, d *schema.ResourceData) bool { +func {{$.ResourceName}}IngressToResourcesDiffSuppressFunc(_, _, _ string, d *schema.ResourceData) bool { old, new := d.GetChange("ingress_to.0.resources") oldResources, err := tpgresource.InterfaceSliceToStringSlice(old) @@ -40,7 +40,7 @@ func {{$.ResourceName}}IngressToResourcesDiffSupressFunc(_, _, _ string, d *sche return slices.Equal(oldResources, newResources) } -func {{$.ResourceName}}IdentityTypeDiffSupressFunc(_, old, new string, _ *schema.ResourceData) bool { +func {{$.ResourceName}}IdentityTypeDiffSuppressFunc(_, old, new string, _ *schema.ResourceData) bool { if old == "" && new == "IDENTITY_TYPE_UNSPECIFIED" { return true } diff --git a/mmv1/templates/terraform/constants/apigee_instance.go.tmpl b/mmv1/templates/terraform/constants/apigee_instance.go.tmpl index c092cf26daed..b87160ab731c 100644 --- a/mmv1/templates/terraform/constants/apigee_instance.go.tmpl +++ b/mmv1/templates/terraform/constants/apigee_instance.go.tmpl @@ -1,4 +1,4 @@ -// Supress diffs when the lists of project have the same number of entries to handle the case that +// Suppress diffs when the lists of project have the same number of entries to handle the case that // API does not return what the user originally provided. Instead, API does some transformation. // For example, user provides a list of project number, but API returns a list of project Id. func projectListDiffSuppress(_, _, _ string, d *schema.ResourceData) bool { @@ -21,4 +21,4 @@ func ProjectListDiffSuppressFunc(d tpgresource.TerraformResourceDataChange) bool log.Printf("[DEBUG] - suppressing diff with oldInt %d, newInt %d", oldInt, newInt) return oldInt == newInt -} \ No newline at end of file +} diff --git a/mmv1/templates/terraform/constants/disk.tmpl b/mmv1/templates/terraform/constants/disk.tmpl index a3947c725250..e73ff28c98bb 100644 --- a/mmv1/templates/terraform/constants/disk.tmpl +++ b/mmv1/templates/terraform/constants/disk.tmpl @@ -1,7 +1,7 @@ {{- if ne $.Compiler "terraformgoogleconversion-codegen" }} -// diffsupress for hyperdisk provisioned_iops -func hyperDiskIopsUpdateDiffSupress(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { +// diffsuppress for hyperdisk provisioned_iops +func hyperDiskIopsUpdateDiffSuppress(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { if !strings.Contains(d.Get("type").(string), "hyperdisk") { resourceSchema := ResourceComputeDisk().Schema for field := range resourceSchema { @@ -24,8 +24,8 @@ func AlwaysDiffSuppress(_, _, _ string, _ *schema.ResourceData) bool { } {{- end }} -// diffsupress for beta and to check change in source_disk attribute -func sourceDiskDiffSupress(_, old, new string, _ *schema.ResourceData) bool { +// diffsuppress for beta and to check change in source_disk attribute +func sourceDiskDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { s1 := strings.TrimPrefix(old, "https://www.googleapis.com/compute/beta") s2 := strings.TrimPrefix(new, "https://www.googleapis.com/compute/v1") if strings.HasSuffix(s1, s2) { @@ -265,3 +265,41 @@ func suppressWindowsFamilyDiff(imageName, familyName string) bool { return strings.Contains(updatedImageName, updatedFamilyString) } + +// ExpandStoragePoolUrl returns a full self link from a partial self link. +func ExpandStoragePoolUrl(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (string, error) { + // It does not try to construct anything from empty. + if v == nil || v.(string) == "" { + return "", nil + } + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return "", err + } + zone, err := tpgresource.GetZone(d, config) + if err != nil { + return "", err + } + + formattedStr := v.(string) + if strings.HasPrefix(v.(string), "/") { + formattedStr = formattedStr[1:] + } + replacedStr := "" + + if strings.HasPrefix(formattedStr, "https://") { + // Anything that starts with a URL scheme is assumed to be a self link worth using. + return formattedStr, nil + } else if strings.HasPrefix(formattedStr, "projects/") { + // If the self link references a project, we'll just stuck the compute prefix on it + replacedStr = config.ComputeBasePath + formattedStr + } else if strings.HasPrefix(formattedStr, "zones/") { + // For regional or zonal resources which include their region or zone, just put the project in front. + replacedStr = config.ComputeBasePath + "projects/" + project + "/" + formattedStr + } else { + // Anything else is assumed to be a zonal resource, with a partial link that begins with the resource name. + replacedStr = config.ComputeBasePath + "projects/" + project + "/zones/" + zone + "/storagePools/" + formattedStr + } + return replacedStr, nil +} \ No newline at end of file diff --git a/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.tmpl b/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.tmpl index e42823418c84..b2eb939c523c 100644 --- a/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.tmpl +++ b/mmv1/templates/terraform/custom_check_destroy/firestore_field.go.tmpl @@ -18,7 +18,7 @@ res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ if err != nil { e := err.(*googleapi.Error) if e.Code == 403 && strings.Contains(e.Message, "Cloud Firestore API has not been used in project") { - // The acceptance test has provisioned the resources under test in a new project, and the destory check is seeing the + // The acceptance test has provisioned the resources under test in a new project, and the destroy check is seeing the // effects of the project not existing. This means the service isn't enabled, and that the resource is definitely destroyed. // We do not return the error in this case - destroy was successful return nil diff --git a/mmv1/templates/terraform/custom_expand/bigtable_app_profile_routing.tmpl b/mmv1/templates/terraform/custom_expand/bigtable_app_profile_routing.tmpl index ec33a04d251c..a0ba33c20f95 100644 --- a/mmv1/templates/terraform/custom_expand/bigtable_app_profile_routing.tmpl +++ b/mmv1/templates/terraform/custom_expand/bigtable_app_profile_routing.tmpl @@ -23,5 +23,12 @@ func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.T obj.ClusterIds = append(obj.ClusterIds, id.(string)) } + affinity, _ := d.GetOkExists("row_affinity") + if affinity != nil && affinity == true { + obj.RowAffinity = &bigtableadmin.RowAffinity{} + } else { + obj.RowAffinity = nil + } + return obj, nil } diff --git a/mmv1/templates/terraform/custom_expand/cloud_iap.tmpl b/mmv1/templates/terraform/custom_expand/cloud_iap.tmpl new file mode 100644 index 000000000000..4aa4b5ead7e2 --- /dev/null +++ b/mmv1/templates/terraform/custom_expand/cloud_iap.tmpl @@ -0,0 +1,28 @@ +{{/* + The license inside this block applies to this file + Copyright 2024 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. +*/ -}} +func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + if isEnabled, ok := original["enabled"]; ok { + if !isEnabled.(bool) { + return nil, nil + } + } + transformed := make(map[string]interface{}) + return transformed, nil +} \ No newline at end of file diff --git a/mmv1/templates/terraform/custom_expand/empty_object_if_set.go.tmpl b/mmv1/templates/terraform/custom_expand/empty_object_if_set.go.tmpl index 7bd0c2ac381c..bec0dc3e6f13 100644 --- a/mmv1/templates/terraform/custom_expand/empty_object_if_set.go.tmpl +++ b/mmv1/templates/terraform/custom_expand/empty_object_if_set.go.tmpl @@ -1,7 +1,7 @@ /* * Expands an empty terraform config into an empty object. * - * Used to differentate a user specifying an empty block versus a null/unset block. + * Used to differentiate a user specifying an empty block versus a null/unset block. * * This is unique from send_empty_value, which will send an explicit null value * for empty configuration blocks. diff --git a/mmv1/templates/terraform/custom_expand/network_services_authz_extensions.tmpl b/mmv1/templates/terraform/custom_expand/network_services_authz_extensions.tmpl new file mode 100644 index 000000000000..377c74156c3c --- /dev/null +++ b/mmv1/templates/terraform/custom_expand/network_services_authz_extensions.tmpl @@ -0,0 +1,15 @@ +{{/* + The license inside this block applies to this file + Copyright 2024 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. +*/ -}} +func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return fmt.Sprintf("projects/%s/locations/%s/authzExtensions/%s", d.Get("project"), d.Get("location"), v), nil +} diff --git a/mmv1/templates/terraform/custom_expand/network_services_authz_policies.tmpl b/mmv1/templates/terraform/custom_expand/network_services_authz_policies.tmpl new file mode 100644 index 000000000000..c9cbc2f96f73 --- /dev/null +++ b/mmv1/templates/terraform/custom_expand/network_services_authz_policies.tmpl @@ -0,0 +1,15 @@ +{{/* + The license inside this block applies to this file + Copyright 2024 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. +*/ -}} +func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return fmt.Sprintf("projects/%s/locations/%s/authzPolicies/%s", d.Get("project"), d.Get("location"), v), nil +} diff --git a/mmv1/templates/terraform/custom_expand/storage_pool_full_url.tmpl b/mmv1/templates/terraform/custom_expand/storage_pool_full_url.tmpl new file mode 100644 index 000000000000..9d7a2df7d6a7 --- /dev/null +++ b/mmv1/templates/terraform/custom_expand/storage_pool_full_url.tmpl @@ -0,0 +1,15 @@ +{{/* + The license inside this block applies to this file + Copyright 2024 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. +*/ -}} +func expand{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return ExpandStoragePoolUrl(v, d, config) +} diff --git a/mmv1/templates/terraform/custom_flatten/accesscontextmanager_serviceperimeters_custom_flatten.go.tmpl b/mmv1/templates/terraform/custom_flatten/accesscontextmanager_serviceperimeters_custom_flatten.go.tmpl index 231fc3f35c04..c6db1de5f7e7 100644 --- a/mmv1/templates/terraform/custom_flatten/accesscontextmanager_serviceperimeters_custom_flatten.go.tmpl +++ b/mmv1/templates/terraform/custom_flatten/accesscontextmanager_serviceperimeters_custom_flatten.go.tmpl @@ -18,6 +18,7 @@ func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.Reso "perimeter_type": flattenAccessContextManagerServicePerimetersServicePerimetersPerimeterType(original["perimeterType"], d, config), "status": flattenAccessContextManagerServicePerimetersServicePerimetersStatus(original["status"], d, config), "spec": flattenAccessContextManagerServicePerimetersServicePerimetersSpec(original["spec"], d, config), + "etag": flattenAccessContextManagerServicePerimetersServicePerimetersEtag(original["etag"], d, config), "use_explicit_dry_run_spec": flattenAccessContextManagerServicePerimetersServicePerimetersUseExplicitDryRunSpec(original["useExplicitDryRunSpec"], d, config), }) } @@ -38,6 +39,10 @@ func flattenAccessContextManagerServicePerimetersServicePerimetersName(v interfa return v } +func flattenAccessContextManagerServicePerimetersServicePerimetersEtag(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func flattenAccessContextManagerServicePerimetersServicePerimetersTitle(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } diff --git a/mmv1/templates/terraform/custom_flatten/bigtable_app_profile_routing.tmpl b/mmv1/templates/terraform/custom_flatten/bigtable_app_profile_routing.tmpl index 510165a22154..8459e087100a 100644 --- a/mmv1/templates/terraform/custom_flatten/bigtable_app_profile_routing.tmpl +++ b/mmv1/templates/terraform/custom_flatten/bigtable_app_profile_routing.tmpl @@ -11,10 +11,15 @@ limitations under the License. */ -}} func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + d.Set("row_affinity", nil) if v == nil { return false } + if v.(map[string]interface{})["rowAffinity"] != nil { + d.Set("row_affinity", true) + } + if v.(map[string]interface{})["clusterIds"] == nil { return true } diff --git a/mmv1/templates/terraform/custom_flatten/cloud_iap.tmpl b/mmv1/templates/terraform/custom_flatten/cloud_iap.tmpl new file mode 100644 index 000000000000..4aed8a59e4b0 --- /dev/null +++ b/mmv1/templates/terraform/custom_flatten/cloud_iap.tmpl @@ -0,0 +1,20 @@ +{{/* + The license inside this block applies to this file + Copyright 2024 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. +*/ -}} +func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + transformed := make(map[string]interface{}) + transformed["enabled"] = true + return []interface{}{transformed} +} \ No newline at end of file diff --git a/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.tmpl b/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.tmpl index 0a72fe1c476a..2bd75559bae0 100644 --- a/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.tmpl +++ b/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.tmpl @@ -6,10 +6,10 @@ if sslCertificates, ok := res["sslCertificates"].([]interface{}); ok && len(sslC regPat, _ := regexp.Compile("//certificatemanager.googleapis.com/projects/(.*)/locations/(.*)/certificates/(.*)") if regPat.MatchString(sslCertificates[0].(string)) { - // It is enough to check only the type of one of the provided certificates beacuse all the certificates should be the same type. + // It is enough to check only the type of one of the provided certificates because all the certificates should be the same type. log.Printf("[DEBUG] The field sslCertificates contains certificateManagerCertificates, the field name will be converted to certificateManagerCertificates") res["certificateManagerCertificates"] = res["sslCertificates"] delete(res, "sslCertificates") } } -return res, nil \ No newline at end of file +return res, nil diff --git a/mmv1/templates/terraform/decoders/compute_target_https_proxy.go.tmpl b/mmv1/templates/terraform/decoders/compute_target_https_proxy.go.tmpl index 0a72fe1c476a..2bd75559bae0 100644 --- a/mmv1/templates/terraform/decoders/compute_target_https_proxy.go.tmpl +++ b/mmv1/templates/terraform/decoders/compute_target_https_proxy.go.tmpl @@ -6,10 +6,10 @@ if sslCertificates, ok := res["sslCertificates"].([]interface{}); ok && len(sslC regPat, _ := regexp.Compile("//certificatemanager.googleapis.com/projects/(.*)/locations/(.*)/certificates/(.*)") if regPat.MatchString(sslCertificates[0].(string)) { - // It is enough to check only the type of one of the provided certificates beacuse all the certificates should be the same type. + // It is enough to check only the type of one of the provided certificates because all the certificates should be the same type. log.Printf("[DEBUG] The field sslCertificates contains certificateManagerCertificates, the field name will be converted to certificateManagerCertificates") res["certificateManagerCertificates"] = res["sslCertificates"] delete(res, "sslCertificates") } } -return res, nil \ No newline at end of file +return res, nil diff --git a/mmv1/templates/terraform/decoders/private_cloud.go.tmpl b/mmv1/templates/terraform/decoders/private_cloud.go.tmpl index 99bb7f71b831..8d0c83573c92 100644 --- a/mmv1/templates/terraform/decoders/private_cloud.go.tmpl +++ b/mmv1/templates/terraform/decoders/private_cloud.go.tmpl @@ -41,7 +41,7 @@ if err != nil { return nil, fmt.Errorf("Error reading management cluster of PrivateCloud: %s", err) } -// There can only be 1 management cluster and if the PC read is successfuly and +// There can only be 1 management cluster and if the PC read is successfully and // we got response from cluster API then it should be present. mgmtClusterObj := clusterResponse["clusters"].([]interface{})[0].(map[string]interface{}) clusterName := mgmtClusterObj["name"].(string) @@ -51,4 +51,4 @@ mgmtClusterObj["clusterId"] = clusterName[strings.LastIndex(clusterName, "/")+1: res["managementCluster"] = mgmtClusterObj -return res, nil \ No newline at end of file +return res, nil diff --git a/mmv1/templates/terraform/encoders/location_from_region.go.tmpl b/mmv1/templates/terraform/encoders/location_from_region.go.tmpl index 316a14641ca7..480ef4152e2a 100644 --- a/mmv1/templates/terraform/encoders/location_from_region.go.tmpl +++ b/mmv1/templates/terraform/encoders/location_from_region.go.tmpl @@ -12,7 +12,7 @@ */ -}} config := meta.(*transport_tpg.Config) if _, ok := d.GetOk("location"); !ok { - location, err := tpgresource.GetRegionFromSchema("region", "zone", d, config) + location, err := tpgresource.GetRegion(d, config) if err != nil { return nil, fmt.Errorf("Cannot determine location: set in this resource, or set provider-level 'region' or 'zone'.") } diff --git a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_egress_policy.tf.tmpl b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_egress_policy.tf.tmpl index 17561629da0e..e1860ca73e44 100644 --- a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_egress_policy.tf.tmpl +++ b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_egress_policy.tf.tmpl @@ -6,7 +6,7 @@ resource "google_access_context_manager_service_perimeter" "storage-perimeter" { restricted_services = ["storage.googleapis.com"] } lifecycle { - ignore_changes = [status[0].resources] + ignore_changes = [spec[0].egress_policies] # Allows egress policies to be managed by google_access_context_manager_service_perimeter_dry_run_egress_policy resources } } diff --git a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_ingress_policy.tf.tmpl b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_ingress_policy.tf.tmpl index df981c843515..aa5170bf275b 100644 --- a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_ingress_policy.tf.tmpl +++ b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_dry_run_ingress_policy.tf.tmpl @@ -6,7 +6,7 @@ resource "google_access_context_manager_service_perimeter" "storage-perimeter" { restricted_services = ["storage.googleapis.com"] } lifecycle { - ignore_changes = [status[0].resources] + ignore_changes = [spec[0].ingress_policies] # Allows ingress policies to be managed by google_access_context_manager_service_perimeter_dry_run_ingress_policy resources } } diff --git a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_egress_policy.tf.tmpl b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_egress_policy.tf.tmpl index 7ea39e59976f..5ac06bed0fa6 100644 --- a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_egress_policy.tf.tmpl +++ b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_egress_policy.tf.tmpl @@ -6,7 +6,7 @@ resource "google_access_context_manager_service_perimeter" "storage-perimeter" { restricted_services = ["storage.googleapis.com"] } lifecycle { - ignore_changes = [status[0].resources] + ignore_changes = [status[0].egress_policies] # Allows ingress policies to be managed by google_access_context_manager_service_perimeter_egress_policy resources } } diff --git a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_ingress_policy.tf.tmpl b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_ingress_policy.tf.tmpl index b54c62bcc207..4f8ec8b25328 100644 --- a/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_ingress_policy.tf.tmpl +++ b/mmv1/templates/terraform/examples/access_context_manager_service_perimeter_ingress_policy.tf.tmpl @@ -6,7 +6,7 @@ resource "google_access_context_manager_service_perimeter" "storage-perimeter" { restricted_services = ["storage.googleapis.com"] } lifecycle { - ignore_changes = [status[0].resources] + ignore_changes = [status[0].ingress_policies] # Allows ingress policies to be managed by google_access_context_manager_service_perimeter_ingress_policy resources } } diff --git a/mmv1/templates/terraform/examples/apigee_developer_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_developer_basic_test.tf.tmpl index 20ef39fa6fae..f029b3c7cc9d 100644 --- a/mmv1/templates/terraform/examples/apigee_developer_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_developer_basic_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_environment_basic_deployment_apiproxy_type_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_environment_basic_deployment_apiproxy_type_test.tf.tmpl index c1e4045d48c5..492c2b30ea43 100644 --- a/mmv1/templates/terraform/examples/apigee_environment_basic_deployment_apiproxy_type_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_environment_basic_deployment_apiproxy_type_test.tf.tmpl @@ -6,9 +6,15 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "servicenetworking" { diff --git a/mmv1/templates/terraform/examples/apigee_environment_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_environment_basic_test.tf.tmpl index ff63f69ed691..b8279c9fc14e 100644 --- a/mmv1/templates/terraform/examples/apigee_environment_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_environment_basic_test.tf.tmpl @@ -6,9 +6,15 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "servicenetworking" { diff --git a/mmv1/templates/terraform/examples/apigee_environment_keystore_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_environment_keystore_test.tf.tmpl index 3806673a0c61..ee1165d353be 100644 --- a/mmv1/templates/terraform/examples/apigee_environment_keystore_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_environment_keystore_test.tf.tmpl @@ -6,9 +6,15 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "servicenetworking" { diff --git a/mmv1/templates/terraform/examples/apigee_environment_patch_update_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_environment_patch_update_test.tf.tmpl index d2bb56710d93..e2fdd30ce7d2 100644 --- a/mmv1/templates/terraform/examples/apigee_environment_patch_update_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_environment_patch_update_test.tf.tmpl @@ -8,11 +8,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -20,6 +26,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { @@ -27,6 +34,7 @@ resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_project_service" "kms" { @@ -34,6 +42,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.servicenetworking] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_attachment_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_attachment_basic_test.tf.tmpl index b70cf9d4d3b4..9152c4ecb430 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_attachment_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_attachment_basic_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_basic_test.tf.tmpl index 2c8e0d988950..b527eecbcc03 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_basic_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_cidr_range_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_cidr_range_test.tf.tmpl index 6136c01baeac..0a90437195a5 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_cidr_range_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_cidr_range_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_full_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_full_test.tf.tmpl index 80ee6da8ae87..09bf0c27d7e2 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_full_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_full_test.tf.tmpl @@ -8,11 +8,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -20,6 +26,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { @@ -27,6 +34,7 @@ resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_project_service" "kms" { @@ -34,6 +42,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.servicenetworking] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_ip_range_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_ip_range_test.tf.tmpl index edb467cc02f5..8ba0a9082658 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_ip_range_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_ip_range_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_instance_service_attachment_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_instance_service_attachment_basic_test.tf.tmpl index 22304c65b5f9..408171881a4e 100644 --- a/mmv1/templates/terraform/examples/apigee_instance_service_attachment_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_instance_service_attachment_basic_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_test.tf.tmpl index 508d8899f826..3580506c56a1 100644 --- a/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_basic_test.tf.tmpl @@ -6,19 +6,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.tmpl index 457d32a0aefa..bb70d9b25d05 100644 --- a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_disable_vpc_peering_test.tf.tmpl @@ -8,11 +8,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -20,6 +26,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "kms" { @@ -27,6 +34,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_kms_key_ring" "apigee_keyring" { diff --git a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_test.tf.tmpl index 4e193a9658bc..100dc5b0e53e 100644 --- a/mmv1/templates/terraform/examples/apigee_organization_cloud_full_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_organization_cloud_full_test.tf.tmpl @@ -8,11 +8,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -20,6 +26,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { @@ -27,6 +34,7 @@ resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_project_service" "kms" { @@ -34,6 +42,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.servicenetworking] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_organization_drz_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_organization_drz_test.tf.tmpl index 269b2bfe70ba..66e111ecbf40 100644 --- a/mmv1/templates/terraform/examples/apigee_organization_drz_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_organization_drz_test.tf.tmpl @@ -12,11 +12,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -24,6 +30,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { @@ -31,6 +38,7 @@ resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_project_service" "kms" { @@ -38,6 +46,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.servicenetworking] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/apigee_organization_retention_test.tf.tmpl b/mmv1/templates/terraform/examples/apigee_organization_retention_test.tf.tmpl index 95f5f38fb758..d7b9535b2484 100644 --- a/mmv1/templates/terraform/examples/apigee_organization_retention_test.tf.tmpl +++ b/mmv1/templates/terraform/examples/apigee_organization_retention_test.tf.tmpl @@ -8,11 +8,17 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { provider = google-beta project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { @@ -20,6 +26,7 @@ resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { @@ -27,6 +34,7 @@ resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_project_service" "kms" { @@ -34,6 +42,7 @@ resource "google_project_service" "kms" { project = google_project.project.project_id service = "cloudkms.googleapis.com" + depends_on = [google_project_service.servicenetworking] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/templates/terraform/examples/artifact_registry_repository_multi_region.tf.tmpl b/mmv1/templates/terraform/examples/artifact_registry_repository_multi_region.tf.tmpl new file mode 100644 index 000000000000..a87e7aa27b54 --- /dev/null +++ b/mmv1/templates/terraform/examples/artifact_registry_repository_multi_region.tf.tmpl @@ -0,0 +1,6 @@ +resource "google_artifact_registry_repository" "{{$.PrimaryResourceId}}" { + repository_id = "{{index $.Vars "repository_id"}}" + description = "{{index $.Vars "desc"}}" + location = "us" + format = "DOCKER" +} diff --git a/mmv1/templates/terraform/examples/beyondcorp_app_connection_basic.tf.tmpl b/mmv1/templates/terraform/examples/beyondcorp_app_connection_basic.tf.tmpl index 4e605c2c8012..1a995efb4be7 100644 --- a/mmv1/templates/terraform/examples/beyondcorp_app_connection_basic.tf.tmpl +++ b/mmv1/templates/terraform/examples/beyondcorp_app_connection_basic.tf.tmpl @@ -3,18 +3,7 @@ resource "google_service_account" "service_account" { display_name = "Test Service Account" } -# wait for service account to propagate -- can be needed due to -# SA eventual consistency issue -resource "time_sleep" "wait_120_seconds" { - depends_on = [google_service_account.service_account] - - create_duration = "120s" -} - - resource "google_beyondcorp_app_connector" "app_connector" { - depends_on = [time_sleep.wait_120_seconds] - name = "{{index $.Vars "app_connector_name"}}" principal_info { service_account { diff --git a/mmv1/templates/terraform/examples/beyondcorp_app_connection_full.tf.tmpl b/mmv1/templates/terraform/examples/beyondcorp_app_connection_full.tf.tmpl index 88d1ea52403d..9224d30b34ef 100644 --- a/mmv1/templates/terraform/examples/beyondcorp_app_connection_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/beyondcorp_app_connection_full.tf.tmpl @@ -3,14 +3,6 @@ resource "google_service_account" "service_account" { display_name = "Test Service Account" } -# wait for service account to propagate -- can be needed due to -# SA eventual consistency issue -resource "time_sleep" "wait_120_seconds" { - depends_on = [google_service_account.service_account] - - create_duration = "120s" -} - resource "google_beyondcorp_app_gateway" "app_gateway" { name = "{{index $.Vars "app_gateway_name"}}" type = "TCP_PROXY" @@ -18,8 +10,6 @@ resource "google_beyondcorp_app_gateway" "app_gateway" { } resource "google_beyondcorp_app_connector" "app_connector" { - depends_on = [time_sleep.wait_120_seconds] - name = "{{index $.Vars "app_connector_name"}}" principal_info { service_account { diff --git a/mmv1/templates/terraform/examples/bigtable_app_profile_row_affinity.tf.tmpl b/mmv1/templates/terraform/examples/bigtable_app_profile_row_affinity.tf.tmpl new file mode 100644 index 000000000000..83145a66fdf9 --- /dev/null +++ b/mmv1/templates/terraform/examples/bigtable_app_profile_row_affinity.tf.tmpl @@ -0,0 +1,37 @@ +resource "google_bigtable_instance" "instance" { + name = "{{index $.Vars "instance_name"}}" + cluster { + cluster_id = "cluster-1" + zone = "us-central1-a" + num_nodes = 3 + storage_type = "HDD" + } + cluster { + cluster_id = "cluster-2" + zone = "us-central1-b" + num_nodes = 3 + storage_type = "HDD" + } + cluster { + cluster_id = "cluster-3" + zone = "us-central1-c" + num_nodes = 3 + storage_type = "HDD" + } + + deletion_protection = "{{index $.Vars "deletion_protection"}}" +} + +resource "google_bigtable_app_profile" "ap" { + instance = google_bigtable_instance.instance.name + app_profile_id = "{{index $.Vars "app_profile_name"}}" + + // Requests will be routed to the following 2 clusters. + multi_cluster_routing_use_any = true + multi_cluster_routing_cluster_ids = ["cluster-1", "cluster-2"] + + row_affinity = true + + ignore_warnings = true +} + diff --git a/mmv1/templates/terraform/examples/composer_user_workloads_config_map_basic.tf.tmpl b/mmv1/templates/terraform/examples/composer_user_workloads_config_map_basic.tf.tmpl index a2641c1bf801..5b53968aac54 100644 --- a/mmv1/templates/terraform/examples/composer_user_workloads_config_map_basic.tf.tmpl +++ b/mmv1/templates/terraform/examples/composer_user_workloads_config_map_basic.tf.tmpl @@ -1,5 +1,4 @@ resource "google_composer_environment" "environment" { - provider = google-beta name = "{{index $.Vars "environment_name"}}" region = "us-central1" config { @@ -10,7 +9,6 @@ resource "google_composer_environment" "environment" { } resource "google_composer_user_workloads_config_map" "{{$.PrimaryResourceId}}" { - provider = google-beta name = "{{index $.Vars "config_map_name"}}" region = "us-central1" environment = google_composer_environment.environment.name diff --git a/mmv1/templates/terraform/examples/firebase_database_instance_default_database.tf.tmpl b/mmv1/templates/terraform/examples/firebase_database_instance_default_database.tf.tmpl index 083fa263b42d..2ded65e3bcd0 100644 --- a/mmv1/templates/terraform/examples/firebase_database_instance_default_database.tf.tmpl +++ b/mmv1/templates/terraform/examples/firebase_database_instance_default_database.tf.tmpl @@ -9,15 +9,32 @@ resource "google_project" "default" { } } +resource "google_project_service" "firebase" { + provider = google-beta + project = google_project.default.project_id + service = "firebase.googleapis.com" + + disable_on_destroy = false +} + resource "google_firebase_project" "default" { provider = google-beta project = google_project.default.project_id + + depends_on = [google_project_service.firebase] } resource "google_project_service" "firebase_database" { provider = google-beta project = google_firebase_project.default.project service = "firebasedatabase.googleapis.com" + + disable_on_destroy = false +} + +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project_service.firebase_database] } resource "google_firebase_database_instance" "default" { @@ -26,5 +43,5 @@ resource "google_firebase_database_instance" "default" { region = "us-central1" instance_id = "{{index $.Vars "project_id"}}-default-rtdb" type = "DEFAULT_DATABASE" - depends_on = [google_project_service.firebase_database] + depends_on = [time_sleep.wait_60_seconds] } diff --git a/mmv1/templates/terraform/examples/firebasehosting_version_headers.tf.tmpl b/mmv1/templates/terraform/examples/firebasehosting_version_headers.tf.tmpl new file mode 100644 index 000000000000..1e21287b9d6d --- /dev/null +++ b/mmv1/templates/terraform/examples/firebasehosting_version_headers.tf.tmpl @@ -0,0 +1,26 @@ +resource "google_firebase_hosting_site" "default" { + provider = google-beta + project = "{{index $.TestEnvVars "project_id"}}" + site_id = "{{index $.Vars "site_id"}}" +} + +resource "google_firebase_hosting_version" "default" { + provider = google-beta + site_id = google_firebase_hosting_site.default.site_id + config { + headers { + # Also okay to use regex + glob = "/headers/**" + headers = { + my-header = "my-value" + } + } + } +} + +resource "google_firebase_hosting_release" "default" { + provider = google-beta + site_id = google_firebase_hosting_site.default.site_id + version_name = google_firebase_hosting_version.default.name + message = "With custom headers" +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/firebasehosting_version_headers_regex.tf.tmpl b/mmv1/templates/terraform/examples/firebasehosting_version_headers_regex.tf.tmpl new file mode 100644 index 000000000000..89d9ebe06502 --- /dev/null +++ b/mmv1/templates/terraform/examples/firebasehosting_version_headers_regex.tf.tmpl @@ -0,0 +1,26 @@ +resource "google_firebase_hosting_site" "default" { + provider = google-beta + project = "{{index $.TestEnvVars "project_id"}}" + site_id = "{{index $.Vars "site_id"}}" +} + +resource "google_firebase_hosting_version" "default" { + provider = google-beta + site_id = google_firebase_hosting_site.default.site_id + config { + headers { + # Also okay to use glob + regex = "^~/headers$" + headers = { + my-header = "my-value" + } + } + } +} + +resource "google_firebase_hosting_release" "default" { + provider = google-beta + site_id = google_firebase_hosting_site.default.site_id + version_name = google_firebase_hosting_version.default.name + message = "With custom headers" +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/gemini_code_repository_index_basic.tf.tmpl b/mmv1/templates/terraform/examples/gemini_code_repository_index_basic.tf.tmpl new file mode 100644 index 000000000000..27e8fa4f41e9 --- /dev/null +++ b/mmv1/templates/terraform/examples/gemini_code_repository_index_basic.tf.tmpl @@ -0,0 +1,6 @@ +resource "google_gemini_code_repository_index" "example" { + provider = google-beta + location = "us-central1" + code_repository_index_id = "{{index $.Vars "cri_id"}}" + kms_key = "projects/projectExample/locations/locationExample/keyRings/keyRingExample/cryptoKeys/cryptoKeyExample" +} diff --git a/mmv1/templates/terraform/examples/gemini_repository_group_basic.tf.tmpl b/mmv1/templates/terraform/examples/gemini_repository_group_basic.tf.tmpl new file mode 100644 index 000000000000..b5a043658356 --- /dev/null +++ b/mmv1/templates/terraform/examples/gemini_repository_group_basic.tf.tmpl @@ -0,0 +1,11 @@ +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{cri_id}" + repository_group_id = "{{index $.Vars "repository_group_id"}}" + repositories { + resource = "{{index $.Vars "repository_resource"}}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} diff --git a/mmv1/templates/terraform/examples/global_forwarding_rule_external_managed.tf.tmpl b/mmv1/templates/terraform/examples/global_forwarding_rule_external_managed.tf.tmpl index 7f9263b0b0f7..951e7a58611a 100644 --- a/mmv1/templates/terraform/examples/global_forwarding_rule_external_managed.tf.tmpl +++ b/mmv1/templates/terraform/examples/global_forwarding_rule_external_managed.tf.tmpl @@ -3,6 +3,7 @@ resource "google_compute_global_forwarding_rule" "default" { target = google_compute_target_http_proxy.default.id port_range = "80" load_balancing_scheme = "EXTERNAL_MANAGED" + network_tier = "PREMIUM" } resource "google_compute_target_http_proxy" "default" { diff --git a/mmv1/templates/terraform/examples/iam_folders_policy_binding.tf.tmpl b/mmv1/templates/terraform/examples/iam_folders_policy_binding.tf.tmpl index 499a0377014b..bd130bf61651 100644 --- a/mmv1/templates/terraform/examples/iam_folders_policy_binding.tf.tmpl +++ b/mmv1/templates/terraform/examples/iam_folders_policy_binding.tf.tmpl @@ -1,5 +1,4 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "{{index $.TestEnvVars "org_id"}}" location = "global" display_name = "{{index $.Vars "display_name"}}" @@ -7,7 +6,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_folder" "folder" { - provider = google-beta display_name = "{{index $.Vars "folder_name"}}" parent = "organizations/{{index $.TestEnvVars "org_id"}}" deletion_protection = false @@ -19,7 +17,6 @@ resource "time_sleep" "wait_120s" { } resource "google_iam_folders_policy_binding" "{{$.PrimaryResourceId}}" { - provider = google-beta folder = google_folder.folder.folder_id location = "global" display_name = "{{index $.Vars "display_name"}}" diff --git a/mmv1/templates/terraform/examples/iam_organizations_policy_binding.tf.tmpl b/mmv1/templates/terraform/examples/iam_organizations_policy_binding.tf.tmpl index 92c60be8aa78..971972842a53 100644 --- a/mmv1/templates/terraform/examples/iam_organizations_policy_binding.tf.tmpl +++ b/mmv1/templates/terraform/examples/iam_organizations_policy_binding.tf.tmpl @@ -1,5 +1,4 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "{{index $.TestEnvVars "org_id"}}" location = "global" display_name = "{{index $.Vars "display_name"}}" @@ -7,7 +6,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_iam_organizations_policy_binding" "{{$.PrimaryResourceId}}" { - provider = google-beta organization = "{{index $.TestEnvVars "org_id"}}" location = "global" display_name = "{{index $.Vars "display_name"}}" diff --git a/mmv1/templates/terraform/examples/iam_principal_access_boundary_policy.tf.tmpl b/mmv1/templates/terraform/examples/iam_principal_access_boundary_policy.tf.tmpl index 0eb3adf7b293..9712903ffc18 100644 --- a/mmv1/templates/terraform/examples/iam_principal_access_boundary_policy.tf.tmpl +++ b/mmv1/templates/terraform/examples/iam_principal_access_boundary_policy.tf.tmpl @@ -1,5 +1,4 @@ resource "google_iam_principal_access_boundary_policy" "{{$.PrimaryResourceId}}" { - provider = google-beta organization = "{{index $.TestEnvVars "org_id"}}" location = "global" display_name = "{{index $.Vars "display_name"}}" diff --git a/mmv1/templates/terraform/examples/iam_projects_policy_binding.tf.tmpl b/mmv1/templates/terraform/examples/iam_projects_policy_binding.tf.tmpl new file mode 100644 index 000000000000..99844724366e --- /dev/null +++ b/mmv1/templates/terraform/examples/iam_projects_policy_binding.tf.tmpl @@ -0,0 +1,22 @@ +data "google_project" "project" { + provider = google +} + +resource "google_iam_principal_access_boundary_policy" "pab_policy" { + organization = "{{index $.TestEnvVars "org_id"}}" + location = "global" + display_name = "{{index $.Vars "display_name"}}" + principal_access_boundary_policy_id = "{{index $.Vars "pab_policy_id"}}" +} + +resource "google_iam_projects_policy_binding" "{{$.PrimaryResourceId}}" { + project = data.google_project.project.project_id + location = "global" + display_name = "{{index $.Vars "display_name"}}" + policy_kind = "PRINCIPAL_ACCESS_BOUNDARY" + policy_binding_id = "{{index $.Vars "project_binding_id"}}" + policy = "organizations/{{index $.TestEnvVars "org_id"}}/locations/global/principalAccessBoundaryPolicies/${google_iam_principal_access_boundary_policy.pab_policy.principal_access_boundary_policy_id}" + target { + principal_set = "//cloudresourcemanager.googleapis.com/projects/${data.google_project.project.project_id}" + } +} diff --git a/mmv1/templates/terraform/examples/integrations_client_advance.tf.tmpl b/mmv1/templates/terraform/examples/integrations_client_advance.tf.tmpl deleted file mode 100644 index b5bc89607923..000000000000 --- a/mmv1/templates/terraform/examples/integrations_client_advance.tf.tmpl +++ /dev/null @@ -1,38 +0,0 @@ -data "google_project" "test_project" { -} - -resource "google_kms_key_ring" "keyring" { - name = "{{index $.Vars "key_ring_name"}}" - location = "us-east1" -} - -resource "google_kms_crypto_key" "cryptokey" { - name = "crypto-key-example" - key_ring = google_kms_key_ring.keyring.id - rotation_period = "7776000s" - depends_on = [google_kms_key_ring.keyring] -} - -resource "google_kms_crypto_key_version" "test_key" { - crypto_key = google_kms_crypto_key.cryptokey.id - depends_on = [google_kms_crypto_key.cryptokey] -} - -resource "google_service_account" "service_account" { - account_id = "service-account-id" - display_name = "Service Account" -} - -resource "google_integrations_client" "{{$.PrimaryResourceId}}" { - location = "us-east1" - create_sample_workflows = true - run_as_service_account = google_service_account.service_account.email - cloud_kms_config { - kms_location = "us-east1" - kms_ring = google_kms_key_ring.keyring.id - key = google_kms_crypto_key.cryptokey.id - key_version = google_kms_crypto_key_version.test_key.id - kms_project_id = data.google_project.test_project.project_id - } - depends_on = [google_kms_crypto_key_version.test_key, google_service_account.service_account] -} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/integrations_client_deprecated_fields.tf.tmpl b/mmv1/templates/terraform/examples/integrations_client_deprecated_fields.tf.tmpl deleted file mode 100644 index bfd93a76ca90..000000000000 --- a/mmv1/templates/terraform/examples/integrations_client_deprecated_fields.tf.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -resource "google_integrations_client" "{{$.PrimaryResourceId}}" { - location = "asia-south1" - provision_gmek = true - create_sample_workflows = true -} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/integrations_client_full.tf.tmpl b/mmv1/templates/terraform/examples/integrations_client_full.tf.tmpl index ce7f13f5124c..d1b097a0dcf9 100644 --- a/mmv1/templates/terraform/examples/integrations_client_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/integrations_client_full.tf.tmpl @@ -27,9 +27,9 @@ resource "google_integrations_client" "{{$.PrimaryResourceId}}" { run_as_service_account = google_service_account.service_account.email cloud_kms_config { kms_location = "us-east1" - kms_ring = google_kms_key_ring.keyring.id - key = google_kms_crypto_key.cryptokey.id - key_version = google_kms_crypto_key_version.test_key.id + kms_ring = basename(google_kms_key_ring.keyring.id) + key = basename(google_kms_crypto_key.cryptokey.id) + key_version = basename(google_kms_crypto_key_version.test_key.id) kms_project_id = data.google_project.test_project.project_id } } \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/network_connectivity_spoke_linked_vpc_network_group.tf.tmpl b/mmv1/templates/terraform/examples/network_connectivity_spoke_linked_vpc_network_group.tf.tmpl new file mode 100644 index 000000000000..1ff1a1695edc --- /dev/null +++ b/mmv1/templates/terraform/examples/network_connectivity_spoke_linked_vpc_network_group.tf.tmpl @@ -0,0 +1,40 @@ +resource "google_compute_network" "network" { + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_network_connectivity_hub" "basic_hub" { + name = "{{index $.Vars "hub_name"}}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_network_connectivity_group" "default_group" { + hub = google_network_connectivity_hub.basic_hub.id + name = "default" + description = "A sample hub group" +} + +resource "google_network_connectivity_spoke" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "spoke_name"}}" + location = "global" + description = "A sample spoke with a linked VPC" + labels = { + label-one = "value-one" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_vpc_network { + exclude_export_ranges = [ + "198.51.100.0/24", + "10.10.0.0/16" + ] + include_export_ranges = [ + "198.51.100.0/23", + "10.0.0.0/8" + ] + uri = google_compute_network.network.self_link + } + group = google_network_connectivity_group.default_group.id +} diff --git a/mmv1/templates/terraform/examples/network_security_intercept_deployment_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_intercept_deployment_basic.tf.tmpl new file mode 100644 index 000000000000..8ed74aaf5be8 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_intercept_deployment_basic.tf.tmpl @@ -0,0 +1,61 @@ +resource "google_compute_network" "network" { + provider = google-beta + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "{{index $.Vars "subnetwork_name"}}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "{{index $.Vars "health_check_name"}}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "{{index $.Vars "backend_service_name"}}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "{{index $.Vars "forwarding_rule_name"}}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" +} + +resource "google_network_security_intercept_deployment_group" "deployment_group" { + provider = google-beta + intercept_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_intercept_deployment" "{{$.PrimaryResourceId}}" { + provider = google-beta + intercept_deployment_id = "{{index $.Vars "deployment_id"}}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + intercept_deployment_group = google_network_security_intercept_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_security_intercept_deployment_group_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_intercept_deployment_group_basic.tf.tmpl new file mode 100644 index 000000000000..511a749d7c37 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_intercept_deployment_group_basic.tf.tmpl @@ -0,0 +1,15 @@ +resource "google_compute_network" "network" { + provider = google-beta + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_network_security_intercept_deployment_group" "{{$.PrimaryResourceId}}" { + provider = google-beta + intercept_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_security_mirroring_deployment_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_mirroring_deployment_basic.tf.tmpl new file mode 100644 index 000000000000..d613368ef4c7 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_mirroring_deployment_basic.tf.tmpl @@ -0,0 +1,62 @@ +resource "google_compute_network" "network" { + provider = google-beta + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "{{index $.Vars "subnetwork_name"}}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "{{index $.Vars "health_check_name"}}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "{{index $.Vars "backend_service_name"}}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "{{index $.Vars "forwarding_rule_name"}}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" + is_mirroring_collector = true +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_deployment" "{{$.PrimaryResourceId}}" { + provider = google-beta + mirroring_deployment_id = "{{index $.Vars "deployment_id"}}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_security_mirroring_deployment_group_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_mirroring_deployment_group_basic.tf.tmpl new file mode 100644 index 000000000000..3797a747b544 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_mirroring_deployment_group_basic.tf.tmpl @@ -0,0 +1,15 @@ +resource "google_compute_network" "network" { + provider = google-beta + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "{{$.PrimaryResourceId}}" { + provider = google-beta + mirroring_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_association_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_association_basic.tf.tmpl new file mode 100644 index 000000000000..d529390fa77e --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_association_basic.tf.tmpl @@ -0,0 +1,36 @@ +resource "google_compute_network" "producer_network" { + provider = google-beta + name = "{{index $.Vars "producer_network_name"}}" + auto_create_subnetworks = false +} + +resource "google_compute_network" "consumer_network" { + provider = google-beta + name = "{{index $.Vars "consumer_network_name"}}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.producer_network.id +} + +resource "google_network_security_mirroring_endpoint_group" "endpoint_group" { + provider = google-beta + mirroring_endpoint_group_id = "{{index $.Vars "endpoint_group_id"}}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id +} + +resource "google_network_security_mirroring_endpoint_group_association" "{{$.PrimaryResourceId}}" { + provider = google-beta + mirroring_endpoint_group_association_id = "{{index $.Vars "endpoint_group_association_id"}}" + location = "global" + network = google_compute_network.consumer_network.id + mirroring_endpoint_group = google_network_security_mirroring_endpoint_group.endpoint_group.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_basic.tf.tmpl new file mode 100644 index 000000000000..95e6a67cb371 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_security_mirroring_endpoint_group_basic.tf.tmpl @@ -0,0 +1,22 @@ +resource "google_compute_network" "network" { + provider = google-beta + name = "{{index $.Vars "network_name"}}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "{{index $.Vars "deployment_group_id"}}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_endpoint_group" "{{$.PrimaryResourceId}}" { + provider = google-beta + mirroring_endpoint_group_id = "{{index $.Vars "endpoint_group_id"}}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} diff --git a/mmv1/templates/terraform/examples/network_services_authz_extension_basic.tf.tmpl b/mmv1/templates/terraform/examples/network_services_authz_extension_basic.tf.tmpl new file mode 100644 index 000000000000..c2050c447ea5 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_services_authz_extension_basic.tf.tmpl @@ -0,0 +1,23 @@ +resource "google_compute_region_backend_service" "default" { + name = "{{index $.Vars "backend_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_network_services_authz_extension" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "resource_name"}}" + project = "{{index $.TestEnvVars "project"}}" + location = "us-west1" + + description = "my description" + load_balancing_scheme = "INTERNAL_MANAGED" + authority = "ext11.com" + service = google_compute_region_backend_service.default.self_link + timeout = "0.1s" + fail_open = false + forward_headers = ["Authorization"] +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/network_services_authz_policy_advanced.tf.tmpl b/mmv1/templates/terraform/examples/network_services_authz_policy_advanced.tf.tmpl new file mode 100644 index 000000000000..e8905548cc37 --- /dev/null +++ b/mmv1/templates/terraform/examples/network_services_authz_policy_advanced.tf.tmpl @@ -0,0 +1,123 @@ +resource "google_compute_network" "default" { + name = "{{index $.Vars "network_name"}}" + project = "{{index $.TestEnvVars "project"}}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "{{index $.Vars "subnet_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + ip_cidr_range = "10.1.2.0/24" + network = google_compute_network.default.id +} + +resource "google_compute_subnetwork" "proxy_only" { + name = "{{index $.Vars "proxy_subnet_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + ip_cidr_range = "10.129.0.0/23" + purpose = "REGIONAL_MANAGED_PROXY" + role = "ACTIVE" + network = google_compute_network.default.id +} + +resource "google_compute_address" "default" { + name = "{{index $.Vars "address_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + subnetwork = google_compute_subnetwork.default.id + address_type = "INTERNAL" + purpose = "GCE_ENDPOINT" +} + +resource "google_compute_region_health_check" "default" { + name = "{{index $.Vars "health_check_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + + http_health_check { + port_specification = "USE_SERVING_PORT" + } +} + +resource "google_compute_region_backend_service" "url_map" { + name = "{{index $.Vars "backend_url_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + + health_checks = [google_compute_region_health_check.default.id] +} + +resource "google_compute_region_url_map" "default" { + name = "{{index $.Vars "url_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + default_service = google_compute_region_backend_service.url_map.id +} + +resource "google_compute_region_target_http_proxy" "default" { + name = "{{index $.Vars "target_proxy_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + url_map = google_compute_region_url_map.default.id +} + +resource "google_compute_forwarding_rule" "default" { + name = "{{index $.Vars "forwarding_rule_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + ip_protocol = "TCP" + port_range = "80" + target = google_compute_region_target_http_proxy.default.id + ip_address = google_compute_address.default.id + + depends_on = [google_compute_subnetwork.proxy_only] +} + +resource "google_compute_region_backend_service" "authz_extension" { + name = "{{index $.Vars "backend_authz_name"}}" + project = "{{index $.TestEnvVars "project"}}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_network_services_authz_extension" "default" { + name = "{{index $.Vars "authz_extension_name"}}" + project = "{{index $.TestEnvVars "project"}}" + location = "us-west1" + + description = "my description" + load_balancing_scheme = "INTERNAL_MANAGED" + authority = "ext11.com" + service = google_compute_region_backend_service.authz_extension.self_link + timeout = "0.1s" + fail_open = false + forward_headers = ["Authorization"] +} + +resource "google_network_security_authz_policy" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "resource_name"}}" + project = "{{index $.TestEnvVars "project"}}" + location = "us-west1" + description = "my description" + + target { + load_balancing_scheme = "INTERNAL_MANAGED" + resources = [ google_compute_forwarding_rule.default.self_link ] + } + + action = "CUSTOM" + custom_provider { + authz_extension { + resources = [ google_network_services_authz_extension.default.id ] + } + } +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_basic.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_basic.tf.tmpl index 69096436f186..42005b473e05 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_basic.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_basic.tf.tmpl @@ -2,7 +2,7 @@ resource "google_oracle_database_autonomous_database" "{{$.PrimaryResourceId}}"{ autonomous_database_id = "{{index $.Vars "autonomous_database_id"}}" location = "us-east4" project = "{{index $.Vars "project"}}" - database = "testdb" + database = "{{index $.Vars "database_name"}}" admin_password = "123Abpassword" network = data.google_compute_network.default.id cidr = "10.5.0.0/24" @@ -13,6 +13,7 @@ resource "google_oracle_database_autonomous_database" "{{$.PrimaryResourceId}}"{ db_workload = "OLTP" license_type = "LICENSE_INCLUDED" } + deletion_protection = "{{index $.Vars "deletion_protection"}}" } data "google_compute_network" "default" { diff --git a/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_full.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_full.tf.tmpl index 18b78f2c0d3e..37837ee9bc32 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_autonomous_database_full.tf.tmpl @@ -3,7 +3,7 @@ resource "google_oracle_database_autonomous_database" "{{$.PrimaryResourceId}}"{ location = "us-east4" project = "{{index $.Vars "project"}}" display_name = "autonomousDatabase displayname" - database = "testdatabase" + database = "{{index $.Vars "database_name"}}" admin_password = "123Abpassword" network = data.google_compute_network.default.id cidr = "10.5.0.0/24" @@ -29,8 +29,9 @@ resource "google_oracle_database_autonomous_database" "{{$.PrimaryResourceId}}"{ email = "xyz@example.com" } private_endpoint_ip = "10.5.0.11" - private_endpoint_label = "testhost" + private_endpoint_label = "{{index $.Vars "endpoint_name"}}" } + deletion_protection = "{{index $.Vars "deletion_protection"}}" } data "google_compute_network" "default" { diff --git a/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_basic.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_basic.tf.tmpl index 69cddcfac019..5ff65d2362e4 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_basic.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_basic.tf.tmpl @@ -8,4 +8,6 @@ resource "google_oracle_database_cloud_exadata_infrastructure" "{{$.PrimaryResou compute_count= "2" storage_count= "3" } + + deletion_protection = "{{index $.Vars "deletion_protection"}}" } diff --git a/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_full.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_full.tf.tmpl index d10f81f7f7ff..7de73ffeb800 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_cloud_exadata_infrastructure_full.tf.tmpl @@ -27,4 +27,6 @@ resource "google_oracle_database_cloud_exadata_infrastructure" "{{$.PrimaryResou labels = { "label-one" = "value-one" } + + deletion_protection = "{{index $.Vars "deletion_protection"}}" } diff --git a/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_basic.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_basic.tf.tmpl index 7ac2edfa9301..a4a7e12f69c5 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_basic.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_basic.tf.tmpl @@ -28,6 +28,8 @@ resource "google_oracle_database_cloud_exadata_infrastructure" "cloudExadataInfr compute_count= "2" storage_count= "3" } + + deletion_protection = "{{index $.Vars "deletion_protection"}}" } data "google_compute_network" "default" { diff --git a/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_full.tf.tmpl b/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_full.tf.tmpl index 3cfe225f6454..7547e02bfc70 100644 --- a/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/oracledatabase_cloud_vmcluster_full.tf.tmpl @@ -49,6 +49,8 @@ resource "google_oracle_database_cloud_exadata_infrastructure" "cloudExadataInfr compute_count= "2" storage_count= "3" } + + deletion_protection = "{{index $.Vars "deletion_protection"}}" } data "google_compute_network" "default" { diff --git a/mmv1/templates/terraform/examples/org_policy_policy_enforce.tf.tmpl b/mmv1/templates/terraform/examples/org_policy_policy_enforce.tf.tmpl index 8441f6dcdc8f..2ba1eeec28ea 100644 --- a/mmv1/templates/terraform/examples/org_policy_policy_enforce.tf.tmpl +++ b/mmv1/templates/terraform/examples/org_policy_policy_enforce.tf.tmpl @@ -1,6 +1,6 @@ resource "google_org_policy_policy" "primary" { - name = "projects/${google_project.basic.name}/policies/iam.disableServiceAccountKeyUpload" - parent = "projects/${google_project.basic.name}" + name = "projects/${google_project.basic.project_id}/policies/iam.disableServiceAccountKeyUpload" + parent = "projects/${google_project.basic.project_id}" spec { rules { diff --git a/mmv1/templates/terraform/examples/org_policy_policy_parameters_enforce.tf.tmpl b/mmv1/templates/terraform/examples/org_policy_policy_parameters_enforce.tf.tmpl new file mode 100644 index 000000000000..73ef6088e186 --- /dev/null +++ b/mmv1/templates/terraform/examples/org_policy_policy_parameters_enforce.tf.tmpl @@ -0,0 +1,18 @@ +resource "google_org_policy_policy" "primary" { + name = "projects/${google_project.basic.name}/policies/compute.managed.restrictDiskCreation" + parent = "projects/${google_project.basic.name}" + + spec { + rules { + enforce = "TRUE" + parameters = jsonencode({"isSizeLimitCheck" : true, "allowedDiskTypes" : ["pd-ssd", "pd-standard"]}) + } + } +} + +resource "google_project" "basic" { + project_id = "id" + name = "id" + org_id = "123456789" + deletion_policy = "DELETE" +} diff --git a/mmv1/templates/terraform/examples/org_policy_policy_project.tf.tmpl b/mmv1/templates/terraform/examples/org_policy_policy_project.tf.tmpl index 7016cda43ed8..08f3a1d74208 100644 --- a/mmv1/templates/terraform/examples/org_policy_policy_project.tf.tmpl +++ b/mmv1/templates/terraform/examples/org_policy_policy_project.tf.tmpl @@ -1,6 +1,6 @@ resource "google_org_policy_policy" "primary" { - name = "projects/${google_project.basic.name}/policies/gcp.resourceLocations" - parent = "projects/${google_project.basic.name}" + name = "projects/${google_project.basic.project_id}/policies/gcp.resourceLocations" + parent = "projects/${google_project.basic.project_id}" spec { rules { diff --git a/mmv1/templates/terraform/examples/region_network_endpoint_group_psc_service_attachment.tf.tmpl b/mmv1/templates/terraform/examples/region_network_endpoint_group_psc_service_attachment.tf.tmpl index 1e5c99e23b09..0bf3fbeec1c5 100644 --- a/mmv1/templates/terraform/examples/region_network_endpoint_group_psc_service_attachment.tf.tmpl +++ b/mmv1/templates/terraform/examples/region_network_endpoint_group_psc_service_attachment.tf.tmpl @@ -39,7 +39,7 @@ resource "google_compute_forwarding_rule" "default" { load_balancing_scheme = "INTERNAL" backend_service = google_compute_region_backend_service.default.id - all_ports = true + ports = ["80", "88", "443"] network = google_compute_network.default.name subnetwork = google_compute_subnetwork.default.name } @@ -61,7 +61,9 @@ resource "google_compute_region_network_endpoint_group" "{{$.PrimaryResourceId}} network_endpoint_type = "PRIVATE_SERVICE_CONNECT" psc_target_service = google_compute_service_attachment.default.self_link - + psc_data { + producer_port = "88" + } network = google_compute_network.default.self_link subnetwork = google_compute_subnetwork.default.self_link } diff --git a/mmv1/templates/terraform/examples/tpu_v2_queued_resource_basic.tf.tmpl b/mmv1/templates/terraform/examples/tpu_v2_queued_resource_basic.tf.tmpl new file mode 100644 index 000000000000..f6bd66fcbcef --- /dev/null +++ b/mmv1/templates/terraform/examples/tpu_v2_queued_resource_basic.tf.tmpl @@ -0,0 +1,19 @@ +resource "google_tpu_v2_queued_resource" "{{$.PrimaryResourceId}}" { + provider = google-beta + + name = "{{index $.Vars "qr_name"}}" + zone = "us-central1-c" + project = "{{index $.TestEnvVars "project"}}" + + tpu { + node_spec { + parent = "projects/{{index $.TestEnvVars "project"}}/locations/us-central1-c" + node_id = "{{index $.Vars "tpu_name"}}" + node { + runtime_version = "tpu-vm-tf-2.13.0" + accelerator_type = "v2-8" + description = "Text description of the TPU." + } + } + } +} diff --git a/mmv1/templates/terraform/examples/tpu_v2_vm_full.tf.tmpl b/mmv1/templates/terraform/examples/tpu_v2_vm_full.tf.tmpl index f42f025d71b5..364d28462122 100644 --- a/mmv1/templates/terraform/examples/tpu_v2_vm_full.tf.tmpl +++ b/mmv1/templates/terraform/examples/tpu_v2_vm_full.tf.tmpl @@ -27,6 +27,7 @@ resource "google_tpu_v2_vm" "{{$.PrimaryResourceId}}" { enable_external_ips = true network = google_compute_network.network.id subnetwork = google_compute_subnetwork.subnet.id + queue_count = 32 } scheduling_config { diff --git a/mmv1/templates/terraform/extra_schema_entry/bigtable_app_profile.go.tmpl b/mmv1/templates/terraform/extra_schema_entry/bigtable_app_profile.go.tmpl index aada9ae9cd0c..d764a92b41e7 100644 --- a/mmv1/templates/terraform/extra_schema_entry/bigtable_app_profile.go.tmpl +++ b/mmv1/templates/terraform/extra_schema_entry/bigtable_app_profile.go.tmpl @@ -18,4 +18,10 @@ Type: schema.TypeString, }, ConflictsWith: []string{"single_cluster_routing"}, -}, \ No newline at end of file +}, +"row_affinity": { + Type: schema.TypeBool, + Optional: true, + Description: `Must be used with multi-cluster routing. If true, then this app profile will use row affinity sticky routing. With row affinity, Bigtable will route single row key requests based on the row key, rather than randomly. Instead, each row key will be assigned to a cluster by Cloud Bigtable, and will stick to that cluster. Choosing this option improves read-your-writes consistency for most requests under most circumstances, without sacrificing availability. Consistency is not guaranteed, as requests may still fail over between clusters in the event of errors or latency.`, + ConflictsWith: []string{"single_cluster_routing"}, +}, diff --git a/mmv1/templates/terraform/iam/iam_attributes.go.tmpl b/mmv1/templates/terraform/iam/iam_attributes.go.tmpl index 0be3e707e4dd..63f48a3da056 100644 --- a/mmv1/templates/terraform/iam/iam_attributes.go.tmpl +++ b/mmv1/templates/terraform/iam/iam_attributes.go.tmpl @@ -1,5 +1,5 @@ {{- $primaryResourceId := $.ExamplePrimaryResourceId }} {{- $ids := $.IamSelfLinkIdentifiers }} -{{- range $i, $attribue := $.IamAttributes}} - {{ $attribue }} = {{ $.IamParentSourceType }}.{{ $primaryResourceId }}.{{ underscore (index $ids $i)}} -{{- end }} \ No newline at end of file +{{- range $i, $attribute := $.IamAttributes}} + {{ $attribute }} = {{ $.IamParentSourceType }}.{{ $primaryResourceId }}.{{ underscore (index $ids $i)}} +{{- end }} diff --git a/mmv1/templates/terraform/post_create/private_cloud.go.tmpl b/mmv1/templates/terraform/post_create/private_cloud.go.tmpl index 9e3058b9fd80..c0c6421900b2 100644 --- a/mmv1/templates/terraform/post_create/private_cloud.go.tmpl +++ b/mmv1/templates/terraform/post_create/private_cloud.go.tmpl @@ -45,10 +45,10 @@ if len(clusterUpdateMask) > 0 { } err = VmwareengineOperationWaitTime( - config, res, project, "Updating Managment Cluster", userAgent, + config, res, project, "Updating Management Cluster", userAgent, d.Timeout(schema.TimeoutUpdate)) if err != nil { return err } -} \ No newline at end of file +} diff --git a/mmv1/templates/terraform/post_update/private_cloud.go.tmpl b/mmv1/templates/terraform/post_update/private_cloud.go.tmpl index 1aa16811314a..8b4ee48a556d 100644 --- a/mmv1/templates/terraform/post_update/private_cloud.go.tmpl +++ b/mmv1/templates/terraform/post_update/private_cloud.go.tmpl @@ -47,10 +47,10 @@ if len(clusterUpdateMask) > 0 { } err = VmwareengineOperationWaitTime( - config, res, project, "Updating Managment Cluster", userAgent, + config, res, project, "Updating Management Cluster", userAgent, d.Timeout(schema.TimeoutUpdate)) if err != nil { return err } -} \ No newline at end of file +} diff --git a/mmv1/templates/terraform/pre_delete/oracledatabase_autonomous_database.go.tmpl b/mmv1/templates/terraform/pre_delete/oracledatabase_autonomous_database.go.tmpl new file mode 100644 index 000000000000..1bc0ab906b6f --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/oracledatabase_autonomous_database.go.tmpl @@ -0,0 +1,3 @@ +if d.Get("deletion_protection").(bool) { + return fmt.Errorf("cannot destroy google_oracle_database_autonomous_database resource with id : %q without setting deletion_protection=false and running `terraform apply`", d.Id()) +} diff --git a/mmv1/templates/terraform/pre_delete/oracledatabase_cloud_exadata_infrastructure.go.tmpl b/mmv1/templates/terraform/pre_delete/oracledatabase_cloud_exadata_infrastructure.go.tmpl new file mode 100644 index 000000000000..3fe310fd1a2c --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/oracledatabase_cloud_exadata_infrastructure.go.tmpl @@ -0,0 +1,3 @@ +if d.Get("deletion_protection").(bool) { + return fmt.Errorf("cannot destroy google_oracle_database_cloud_exadata_infrastructure resource with id : %q without setting deletion_protection=false and running `terraform apply`", d.Id()) +} diff --git a/mmv1/templates/terraform/pre_update/access_context_manager_service_perimeter.go.tmpl b/mmv1/templates/terraform/pre_update/access_context_manager_service_perimeter.go.tmpl new file mode 100644 index 000000000000..f1204301fd06 --- /dev/null +++ b/mmv1/templates/terraform/pre_update/access_context_manager_service_perimeter.go.tmpl @@ -0,0 +1,5 @@ +if _, ok := d.GetOkExists("etag"); ok { + updateMask = append(updateMask, "etag") + + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) +} diff --git a/mmv1/templates/terraform/pre_update/datastream_stream.go.tmpl b/mmv1/templates/terraform/pre_update/datastream_stream.go.tmpl index abe6ebfe8c38..46ce5cca96ae 100644 --- a/mmv1/templates/terraform/pre_update/datastream_stream.go.tmpl +++ b/mmv1/templates/terraform/pre_update/datastream_stream.go.tmpl @@ -23,7 +23,7 @@ if err != nil { return err } -// lables and terraform_labels fields are overriden with the labels before updating inside the function waitForDatastreamStreamReady +// lables and terraform_labels fields are overridden with the labels before updating inside the function waitForDatastreamStreamReady labels := d.Get("labels") terraformLabels := d.Get("terraform_labels") @@ -36,4 +36,4 @@ if err := d.Set("labels", labels); err != nil { } if err := d.Set("terraform_labels", terraformLabels); err != nil { return fmt.Errorf("Error setting back terraform_labels field: %s", err) -} \ No newline at end of file +} diff --git a/mmv1/templates/terraform/pre_update/privateca_certificate_authority.go.tmpl b/mmv1/templates/terraform/pre_update/privateca_certificate_authority.go.tmpl index a921cf480800..6762a1bc5c4a 100644 --- a/mmv1/templates/terraform/pre_update/privateca_certificate_authority.go.tmpl +++ b/mmv1/templates/terraform/pre_update/privateca_certificate_authority.go.tmpl @@ -41,3 +41,19 @@ if d.HasChange("desired_state") { } } } + + +// `subordinateConfig.certificateAuthority` is not directly passed +// to the backend when activating a sub-CA. Instead, it is used to sign CA cert +// and activate the sub-CA at client side. See b/332548736 for details. +// Drop this field to avoid both `subordinateConfig.certificateAuthority` +// and `subordinateConfig.pemIssuerChain` to be passed to the backend. +if _, ok := obj["subordinateConfig"]; ok { + subConfig := obj["subordinateConfig"].(map[string]interface{}) + // There could be case which a sub-CA was activated via `subordinateConfig.certificateAuthority` + // directly by older version of providers. + // For backward compatibility, delete `certificateAuthority` only if `pemIssuerChain` is presented. + if _, ok := subConfig["pemIssuerChain"]; ok { + delete(subConfig, "certificateAuthority") + } +} diff --git a/mmv1/templates/terraform/resource.html.markdown.tmpl b/mmv1/templates/terraform/resource.html.markdown.tmpl index 1ae18803e773..112e6c098780 100644 --- a/mmv1/templates/terraform/resource.html.markdown.tmpl +++ b/mmv1/templates/terraform/resource.html.markdown.tmpl @@ -148,6 +148,9 @@ In addition to the arguments listed above, the following computed attributes are * `self_link` - The URI of the created resource. {{ "" }} {{- end }} +{{- if $.Docs.Attributes }} +{{ $.Docs.Attributes }} +{{- end }} {{ range $p := $.AllUserProperties }} {{- if $p.Output }} {{- trimTemplate "nested_property_documentation.html.markdown.tmpl" $p }} diff --git a/mmv1/templates/terraform/state_migrations/compute_ha_vpn_gateway.go.tmpl b/mmv1/templates/terraform/state_migrations/compute_ha_vpn_gateway.go.tmpl new file mode 100644 index 000000000000..7b5e40fc3697 --- /dev/null +++ b/mmv1/templates/terraform/state_migrations/compute_ha_vpn_gateway.go.tmpl @@ -0,0 +1,119 @@ +func resourceComputeHaVpnGatewayResourceV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidateGCEName, + Description: `Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and +match the regular expression '[a-z]([-a-z0-9]*[a-z0-9])?' which means +the first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash.`, + }, + "network": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + Description: `The network this VPN gateway is accepting traffic for.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `An optional description of this resource.`, + }, + "gateway_ip_version": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"IPV4", "IPV6", ""}), + Description: `The IP family of the gateway IPs for the HA-VPN gateway interfaces. If not specified, IPV4 will be used. Default value: "IPV4" Possible values: ["IPV4", "IPV6"]`, + Default: "IPV4", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + Description: `The region this gateway should sit in.`, + }, + "stack_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"IPV4_ONLY", "IPV4_IPV6", "IPV6_ONLY", ""}), + Description: `The stack type for this VPN gateway to identify the IP protocols that are enabled. +If not specified, IPV4_ONLY will be used. Default value: "IPV4_ONLY" Possible values: ["IPV4_ONLY", "IPV4_IPV6", "IPV6_ONLY"]`, + Default: "IPV4_ONLY", + }, + "vpn_interfaces": { + Type: schema.TypeList, + Computed: true, + Optional: true, + ForceNew: true, + Description: `A list of interfaces on this VPN gateway.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: `The numeric ID of this VPN gateway interface.`, + }, + "interconnect_attachment": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + Description: `URL of the interconnect attachment resource. When the value +of this field is present, the VPN Gateway will be used for +IPsec-encrypted Cloud Interconnect; all Egress or Ingress +traffic for this VPN Gateway interface will go through the +specified interconnect attachment resource. + +Not currently available publicly.`, + }, + "ip_address": { + Type: schema.TypeString, + Computed: true, + Description: `The external IP address for this VPN gateway interface.`, + }, + }, + }, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + UseJSONNumber: true, + } +} + +func ResourceComputeHaVpnGatewayUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + log.Printf("[DEBUG] Attributes before migration: %#v", rawState) + + + // Check if "gateway_ip_version" already exists + if _, ok := rawState["gateway_ip_version"]; !ok { + // Add the missing attribute with the default value + rawState["gateway_ip_version"] = "IPV4" + } else { + log.Printf("[DEBUG] 'gateway_ip_version' already exists: %#v", rawState["gateway_ip_version"]) + } + + log.Printf("[DEBUG] Attributes after migration: %#v", rawState) + return rawState, nil +} \ No newline at end of file diff --git a/mmv1/templates/tgc_v6/cai2hcl/resource_converters.go.tmpl b/mmv1/templates/tgc_v6/cai2hcl/resource_converters.go.tmpl new file mode 100644 index 000000000000..debc5e74b9dc --- /dev/null +++ b/mmv1/templates/tgc_v6/cai2hcl/resource_converters.go.tmpl @@ -0,0 +1,28 @@ +{{/* The license inside this block applies to this file + Copyright 2024 Google LLC. All Rights Reserved. + + 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. */ -}} +// ---------------------------------------------------------------------------- +// +// *** 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 converters diff --git a/mmv1/templates/tgc_v6/tfplan2cai/resource_converters.go.tmpl b/mmv1/templates/tgc_v6/tfplan2cai/resource_converters.go.tmpl new file mode 100644 index 000000000000..debc5e74b9dc --- /dev/null +++ b/mmv1/templates/tgc_v6/tfplan2cai/resource_converters.go.tmpl @@ -0,0 +1,28 @@ +{{/* The license inside this block applies to this file + Copyright 2024 Google LLC. All Rights Reserved. + + 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. */ -}} +// ---------------------------------------------------------------------------- +// +// *** 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 converters diff --git a/mmv1/third_party/terraform/.teamcity/components/constants.kt b/mmv1/third_party/terraform/.teamcity/components/constants.kt index bb1bca75d390..76d2209ea1d0 100644 --- a/mmv1/third_party/terraform/.teamcity/components/constants.kt +++ b/mmv1/third_party/terraform/.teamcity/components/constants.kt @@ -17,7 +17,7 @@ const val DefaultParallelism = 6 // specifies the default version of Terraform Core which should be used for testing // this is updated semi-regularly -const val DefaultTerraformCoreVersion = "1.8.3" +const val DefaultTerraformCoreVersion = "1.10.0" // This represents a cron view of days of the week const val DefaultDaysOfWeek = "*" diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt index b025568eac6d..be44dcb96987 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt @@ -416,6 +416,11 @@ var ServicesListBeta = mapOf( "displayName" to "Firestore", "path" to "./google-beta/services/firestore" ), + "gemini" to mapOf( + "name" to "gemini", + "displayName" to "Gemini", + "path" to "./google-beta/services/gemini" + ), "gkebackup" to mapOf( "name" to "gkebackup", "displayName" to "Gkebackup", diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt index 5087bad11881..817c79f96f11 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt @@ -411,6 +411,11 @@ var ServicesListGa = mapOf( "displayName" to "Firestore", "path" to "./google/services/firestore" ), + "gemini" to mapOf( + "name" to "gemini", + "displayName" to "Gemini", + "path" to "./google/services/gemini" + ), "gkebackup" to mapOf( "name" to "gkebackup", "displayName" to "Gkebackup", diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-ephemeral-resource.kt b/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-ephemeral-resource.kt deleted file mode 100644 index 16b262454858..000000000000 --- a/mmv1/third_party/terraform/.teamcity/components/projects/feature_branches/FEATURE-BRANCH-ephemeral-resource.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: MPL-2.0 - */ - -// This file is maintained in the GoogleCloudPlatform/magic-modules repository and copied into the downstream provider repositories. Any changes to this file in the downstream will be overwritten. - -package projects.feature_branches - -import ProviderNameBeta -import ProviderNameGa -import SharedResourceNameBeta -import SharedResourceNameGa -import SharedResourceNameVcr -import builds.* -import generated.ServicesListBeta -import generated.ServicesListGa -import jetbrains.buildServer.configs.kotlin.Project -import replaceCharsId -import vcs_roots.HashiCorpVCSRootBeta -import vcs_roots.HashiCorpVCSRootGa -import vcs_roots.ModularMagicianVCSRootBeta -import vcs_roots.ModularMagicianVCSRootGa - -const val featureBranchEphemeralResources = "FEATURE-BRANCH-ephemeral-resource" -const val EphemeralResourcesTfCoreVersion = "1.10.0-rc2" - -// featureBranchEphemeralResourcesSubProject creates a project just for testing ephemeral resources. -// We know that all ephemeral resources we're adding are part of the Resource Manager service, so we only include those builds. -// We create builds for testing the resourcemanager service: -// - Against the GA hashicorp repo -// - Against the GA modular-magician repo -// - Against the Beta hashicorp repo -// - Against the Beta modular-magician repo -// These resemble existing projects present in TeamCity, but these all use a more recent version of Terraform including -// the new ephemeral values feature. -fun featureBranchEphemeralResourcesSubProject(allConfig: AllContextParameters): Project { - - val projectId = replaceCharsId(featureBranchEphemeralResources) - - val packageName = "resourcemanager" // All ephemeral resources will be in the resourcemanager package - val vcrConfig = getVcrAcceptanceTestConfig(allConfig) // Reused below for both MM testing build configs - val trigger = NightlyTriggerConfiguration( - branch = "refs/heads/$featureBranchEphemeralResources" // triggered builds must test the feature branch - ) - - - // GA - val gaConfig = getGaAcceptanceTestConfig(allConfig) - // How to make only build configuration to the relevant package(s) - val resourceManagerPackageGa = ServicesListGa.getValue(packageName) - - // Enable testing using hashicorp/terraform-provider-google - var parentId = "${projectId}_HC_GA" - val buildConfigHashiCorpGa = BuildConfigurationForSinglePackage(packageName, resourceManagerPackageGa.getValue("path"), "Ephemeral resources in $packageName (GA provider, HashiCorp downstream)", ProviderNameGa, parentId, HashiCorpVCSRootGa, listOf(SharedResourceNameGa), gaConfig) - buildConfigHashiCorpGa.addTrigger(trigger) - - // Enable testing using modular-magician/terraform-provider-google - parentId = "${projectId}_MM_GA" - val buildConfigModularMagicianGa = BuildConfigurationForSinglePackage(packageName, resourceManagerPackageGa.getValue("path"), "Ephemeral resources in $packageName (GA provider, MM upstream)", ProviderNameGa, parentId, ModularMagicianVCSRootGa, listOf(SharedResourceNameVcr), vcrConfig) - // No trigger added here (MM upstream is manual only) - - // Beta - val betaConfig = getBetaAcceptanceTestConfig(allConfig) - val resourceManagerPackageBeta = ServicesListBeta.getValue(packageName) - - // Enable testing using hashicorp/terraform-provider-google-beta - parentId = "${projectId}_HC_BETA" - val buildConfigHashiCorpBeta = BuildConfigurationForSinglePackage(packageName, resourceManagerPackageBeta.getValue("path"), "Ephemeral resources in $packageName (Beta provider, HashiCorp downstream)", ProviderNameBeta, parentId, HashiCorpVCSRootBeta, listOf(SharedResourceNameBeta), betaConfig) - buildConfigHashiCorpBeta.addTrigger(trigger) - - // Enable testing using modular-magician/terraform-provider-google-beta - parentId = "${projectId}_MM_BETA" - val buildConfigModularMagicianBeta = BuildConfigurationForSinglePackage(packageName, resourceManagerPackageBeta.getValue("path"), "Ephemeral resources in $packageName (Beta provider, MM upstream)", ProviderNameBeta, parentId, ModularMagicianVCSRootBeta, listOf(SharedResourceNameVcr), vcrConfig) - // No trigger added here (MM upstream is manual only) - - - // ------ - - // Make all builds use a 1.10.0-ish version of TF core - val allBuildConfigs = listOf(buildConfigHashiCorpGa, buildConfigModularMagicianGa, buildConfigHashiCorpBeta, buildConfigModularMagicianBeta) - allBuildConfigs.forEach{ b -> - b.overrideTerraformCoreVersion(EphemeralResourcesTfCoreVersion) - } - - // ------ - - return Project{ - id(projectId) - name = featureBranchEphemeralResources - description = "Subproject for testing feature branch $featureBranchEphemeralResources" - - // Register all build configs in the project - allBuildConfigs.forEach{ b -> - buildType(b) - } - - params { - readOnlySettings() - } - } -} diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt index d0a4308a2702..c551f8f20fd2 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt @@ -18,7 +18,6 @@ import generated.ServicesListBeta import generated.ServicesListGa import jetbrains.buildServer.configs.kotlin.Project import jetbrains.buildServer.configs.kotlin.sharedResource -import projects.feature_branches.featureBranchEphemeralResourcesSubProject // googleCloudRootProject returns a root project that contains a subprojects for the GA and Beta version of the // Google provider. There are also resources to help manage the test projects used for acceptance tests. @@ -64,8 +63,6 @@ fun googleCloudRootProject(allConfig: AllContextParameters): Project { subProject(projectSweeperSubProject(allConfig)) // Feature branch-testing projects - these will be added and removed as needed - subProject(featureBranchEphemeralResourcesSubProject(allConfig)) - params { readOnlySettings() diff --git a/mmv1/third_party/terraform/.teamcity/tests/FEATURE-BRANCH-ephemeral-resource.kt b/mmv1/third_party/terraform/.teamcity/tests/FEATURE-BRANCH-ephemeral-resource.kt deleted file mode 100644 index 9b52c2c9d2fe..000000000000 --- a/mmv1/third_party/terraform/.teamcity/tests/FEATURE-BRANCH-ephemeral-resource.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) HashiCorp, Inc. - * SPDX-License-Identifier: MPL-2.0 - */ - -// This file is maintained in the GoogleCloudPlatform/magic-modules repository and copied into the downstream provider repositories. Any changes to this file in the downstream will be overwritten. - -package tests - -import jetbrains.buildServer.configs.kotlin.triggers.ScheduleTrigger -import org.junit.Assert -import org.junit.Test -import projects.feature_branches.featureBranchEphemeralResources -import projects.googleCloudRootProject - -class FeatureBranchEphemeralResourcesSubProject { - @Test - fun buildsUsingHashiCorpReposAreOnSchedule() { - val root = googleCloudRootProject(testContextParameters()) - - // Find feature branch project - val project = getSubProject(root, featureBranchEphemeralResources) - - // All builds using the HashiCorp owned GitHub repos - val hashiBuilds = project.buildTypes.filter { bt -> - bt.name.contains("HashiCorp downstream") - } - - hashiBuilds.forEach{bt -> - Assert.assertTrue( - "Build configuration `${bt.name}` should contain at least one trigger", - bt.triggers.items.isNotEmpty() - ) - // Look for at least one CRON trigger - var found = false - lateinit var schedulingTrigger: ScheduleTrigger - for (item in bt.triggers.items){ - if (item.type == "schedulingTrigger") { - schedulingTrigger = item as ScheduleTrigger - found = true - break - } - } - - Assert.assertTrue( - "Build configuration `${bt.name}` should contain a CRON/'schedulingTrigger' trigger", - found - ) - - // Check that triggered builds are being run on the feature branch - val isCorrectBranch: Boolean = schedulingTrigger.branchFilter == "+:refs/heads/$featureBranchEphemeralResources" - - Assert.assertTrue( - "Build configuration `${bt.name}` is using the $featureBranchEphemeralResources branch filter", - isCorrectBranch - ) - } - } - - @Test - fun buildsUsingModularMagicianReposAreNotTriggered() { - val root = googleCloudRootProject(testContextParameters()) - - // Find feature branch project - val project = getSubProject(root, featureBranchEphemeralResources) - - // All builds using the HashiCorp owned GitHub repos - val magicianBuilds = project.buildTypes.filter { bt -> - bt.name.contains("MM upstream") - } - - magicianBuilds.forEach{bt -> - Assert.assertTrue( - "Build configuration `${bt.name}` should not have any triggers", - bt.triggers.items.isEmpty() - ) - } - } -} diff --git a/mmv1/third_party/terraform/acctest/bootstrap_test_utils.go.tmpl b/mmv1/third_party/terraform/acctest/bootstrap_test_utils.go.tmpl index b9582f8e1fe7..f82858c15fab 100644 --- a/mmv1/third_party/terraform/acctest/bootstrap_test_utils.go.tmpl +++ b/mmv1/third_party/terraform/acctest/bootstrap_test_utils.go.tmpl @@ -9,6 +9,10 @@ import ( "strings" "testing" "time" +{{ if ne $.TargetVersionName `ga` -}} + // For beta tests only + "net/http" +{{- end }} "github.com/hashicorp/terraform-provider-google/google/envvar" tpgcompute "github.com/hashicorp/terraform-provider-google/google/services/compute" @@ -497,14 +501,14 @@ func NewServiceNetworkSettings(options ...func(*ServiceNetworkSettings)) *Servic // BootstrapSharedServiceNetworkingConnection returns a persistent compute network name // for a test or set of tests. // -// To delete a service networking conneciton, all of the service instances that use that connection +// To delete a service networking connection, all of the service instances that use that connection // must be deleted first. After the service instances are deleted, some service producers delay the deletion // utnil a waiting period has passed. For example, after four days that you delete a SQL instance, // the service networking connection can be deleted. -// That is the reason to use the shared service networking connection for thest resources. +// That is the reason to use the shared service networking connection for test resources. // https://cloud.google.com/vpc/docs/configure-private-services-access#removing-connection // -// testId specifies the test for which a shared network and a gobal address are used/initialized. +// testId specifies the test for which a shared network and a global address are used/initialized. func BootstrapSharedServiceNetworkingConnection(t *testing.T, testId string, params ...func(*ServiceNetworkSettings)) string { settings := NewServiceNetworkSettings(params...) parentService := "services/" + settings.ParentService @@ -1435,6 +1439,319 @@ func SetupProjectsAndGetAccessToken(org, billing, pid, service string, config *t return accessToken, nil } +{{ if ne $.TargetVersionName `ga` -}} + // For bootstrapping Developer Connect git repository link + const SharedGitRepositoryLinkIdPrefix = "tf-bootstrap-git-repository-" + + func BootstrapGitRepository(t *testing.T, gitRepositoryLinkId, location, cloneUri, parentConnectionId string) string { + gitRepositoryLinkId = SharedGitRepositoryLinkIdPrefix + gitRepositoryLinkId + + config := BootstrapConfig(t) + if config == nil { + t.Fatal("Could not bootstrap config.") + } + + log.Printf("[DEBUG] Getting shared git repository link %q", gitRepositoryLinkId) + + getURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s/gitRepositoryLinks/%s", + config.DeveloperConnectBasePath, config.Project, location, parentConnectionId, gitRepositoryLinkId) + + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Headers: headers, + }) + + if err != nil && transport_tpg.IsGoogleApiErrorWithCode(err, 404) { + log.Printf("[DEBUG] Git repository link %q not found, bootstrapping", gitRepositoryLinkId) + obj := map[string]interface{}{ + "clone_uri": cloneUri, + "annotations": map[string]string{}, + } + + postURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s/gitRepositoryLinks?gitRepositoryLinkId=%s", + config.DeveloperConnectBasePath, config.Project, location, parentConnectionId, gitRepositoryLinkId) + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: config.Project, + RawURL: postURL, + UserAgent: config.UserAgent, + Body: obj, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error bootstrapping git repository link %q: %s", gitRepositoryLinkId, err) + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error getting git repository link %q: %s", gitRepositoryLinkId, err) + } + } + + return gitRepositoryLinkId + } + + const SharedConnectionIdPrefix = "tf-bootstrap-developer-connect-connection-" + + // For bootstrapping Developer Connect connection resources + func BootstrapDeveloperConnection(t *testing.T, connectionId, location, tokenResource string, appInstallationId int) string { + connectionId = SharedConnectionIdPrefix + connectionId + + config := BootstrapConfig(t) + if config == nil { + t.Fatal("Could not bootstrap config.") + } + + log.Printf("[DEBUG] Getting shared developer connection %q", connectionId) + + getURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s", + config.DeveloperConnectBasePath, config.Project, location, connectionId) + + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Headers: headers, + }) + + if err != nil { + log.Printf("[DEBUG] Developer connection %q not found, bootstrapping", connectionId) + authorizerCredential := map[string]string{ + "oauth_token_secret_version": tokenResource, + } + githubConfig := map[string]interface{}{ + "github_app": "DEVELOPER_CONNECT", + "app_installation_id": appInstallationId, + "authorizer_credential": authorizerCredential, + } + obj := map[string]interface{}{ + "disabled": false, + "github_config": githubConfig, + } + + postURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections?connectionId=%s", + config.DeveloperConnectBasePath, config.Project, location, connectionId) + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: config.Project, + RawURL: postURL, + UserAgent: config.UserAgent, + Body: obj, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error bootstrapping developer connection %q: %s", connectionId, err) + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error getting developer connection %q: %s", connectionId, err) + } + } + + return connectionId + } + + const SharedRepositoryGroupPrefix = "tf-bootstrap-repo-group-" + + func BoostrapSharedRepositoryGroup(t *testing.T, repositoryGroupId, location, labels, codeRepositoryIndexId, resource string) string { + repositoryGroupId = SharedRepositoryGroupPrefix + repositoryGroupId + + config := BootstrapConfig(t) + if config == nil { + t.Fatal("Could not bootstrap config.") + } + + log.Printf("[DEBUG] Getting shared repository group %q", repositoryGroupId) + + getURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s", + config.GeminiBasePath, config.Project, location, codeRepositoryIndexId, repositoryGroupId) + + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Headers: headers, + }) + if err != nil { + log.Printf("[DEBUG] Repository group %q not found, bootstrapping", codeRepositoryIndexId) + repositories := [1]interface{}{map[string]string{ + "resource": resource, + "branch_pattern": "main", + }} + postURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups?repositoryGroupId=%s", + config.GeminiBasePath, config.Project, location, codeRepositoryIndexId, repositoryGroupId) + obj := map[string]interface{}{ + "repositories": repositories, + } + if labels != "" { + obj["labels"] = labels + } + + headers := make(http.Header) + for { + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: config.Project, + RawURL: postURL, + UserAgent: config.UserAgent, + Body: obj, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + if transport_tpg.IsGoogleApiErrorWithCode(err, 409) { + errMsg := fmt.Sprintf("%s", err) + if strings.Contains(errMsg, "unable to queue the operation") { + log.Printf("[DEBUG] Waiting for enqueued operation to finish before creating RepositoryGroup: %#v", obj) + time.Sleep(10 * time.Second) + } else if strings.Contains(errMsg, "parent resource not in ready state") { + log.Printf("[DEBUG] Waiting for parent resource to become active before creating RepositoryGroup: %#v", obj) + time.Sleep(1 * time.Minute) + } else { + t.Fatalf("Error creating RepositoryGroup: %s", err) + } + } else { + t.Fatalf("Error creating repository group %q: %s", repositoryGroupId, err) + } + } else { + break + } + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Timeout: 20 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Errorf("Error getting repository group %q: %s", repositoryGroupId, err) + } + } + + return repositoryGroupId + } + + // BootstrapSharedCodeRepositoryIndex will create a code repository index + // if it hasn't been created in the test project. + // + // BootstrapSharedCodeRepositoryIndex returns a persistent code repository index + // for a test or set of tests. + // + // Deletion of code repository index takes a few minutes, and creation of it + // currently takes about half an hour. + // That is the reason to use the shared code repository indexes for test resources. + const SharedCodeRepositoryIndexPrefix = "tf-bootstrap-cri-" + + func BootstrapSharedCodeRepositoryIndex(t *testing.T, codeRepositoryIndexId, location, kmsKey string, labels map[string]string) string { + codeRepositoryIndexId = SharedCodeRepositoryIndexPrefix + codeRepositoryIndexId + + config := BootstrapConfig(t) + if config == nil { + t.Fatal("Could not bootstrap config.") + } + + log.Printf("[DEBUG] Getting shared code repository index %q", codeRepositoryIndexId) + + getURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s", config.GeminiBasePath, config.Project, location, codeRepositoryIndexId) + + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Timeout: 90 * time.Minute, + Headers: headers, + }) + + // CRI not found responds with 404 not found + if err != nil && transport_tpg.IsGoogleApiErrorWithCode(err, 404) { + log.Printf("[DEBUG] Code repository index %q not found, bootstrapping", codeRepositoryIndexId) + postURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes?codeRepositoryIndexId=%s", config.GeminiBasePath, config.Project, location, codeRepositoryIndexId) + obj := make(map[string]interface{}) + if labels != nil { + obj["labels"] = labels + } + if kmsKey != "" { + obj["kmsKey"] = kmsKey + } + + headers := make(http.Header) + _, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: config.Project, + RawURL: postURL, + UserAgent: config.UserAgent, + Body: obj, + Timeout: 90 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error creating code repository index %q: %s", codeRepositoryIndexId, err) + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: getURL, + UserAgent: config.UserAgent, + Timeout: 90 * time.Minute, + Headers: headers, + }) + if err != nil { + t.Fatalf("Error getting code repository index %q: %s", codeRepositoryIndexId, err) + } + } else if err != nil { + t.Fatalf("Error getting code repository index %q: %s", codeRepositoryIndexId, err) + } + + return codeRepositoryIndexId + } + +{{- end }} + const sharedTagKeyPrefix = "tf-bootstrap-tagkey" func BootstrapSharedTestTagKey(t *testing.T, testId string) string { diff --git a/mmv1/third_party/terraform/acctest/framework_test_utils.go.tmpl b/mmv1/third_party/terraform/acctest/framework_test_utils.go.tmpl deleted file mode 100644 index 4d4f113343ca..000000000000 --- a/mmv1/third_party/terraform/acctest/framework_test_utils.go.tmpl +++ /dev/null @@ -1,27 +0,0 @@ -package acctest - -import ( - "context" - "log" - "testing" - - "github.com/hashicorp/terraform-plugin-framework/diag" -) - -func GetFwTestProvider(t *testing.T) *frameworkTestProvider { - configsLock.RLock() - fwProvider, ok := fwProviders[t.Name()] - configsLock.RUnlock() - if ok { - return fwProvider - } - - var diags diag.Diagnostics - p := NewFrameworkTestProvider(t.Name()) - configureApiClient(context.Background(), &p.FrameworkProvider, &diags) - if diags.HasError() { - log.Fatalf("%d errors when configuring test provider client: first is %s", diags.ErrorsCount(), diags.Errors()[0].Detail()) - } - - return p -} diff --git a/mmv1/third_party/terraform/acctest/provider_test_utils.go b/mmv1/third_party/terraform/acctest/provider_test_utils.go index f30086539c1d..81bc0fd80a1d 100644 --- a/mmv1/third_party/terraform/acctest/provider_test_utils.go +++ b/mmv1/third_party/terraform/acctest/provider_test_utils.go @@ -20,7 +20,6 @@ var testAccProvider *schema.Provider func init() { configs = make(map[string]*transport_tpg.Config) - fwProviders = make(map[string]*frameworkTestProvider) sources = make(map[string]VcrSource) testAccProvider = provider.Provider() TestAccProviders = map[string]*schema.Provider{ diff --git a/mmv1/third_party/terraform/acctest/test_utils.go.tmpl b/mmv1/third_party/terraform/acctest/test_utils.go.tmpl index 69d453d068ef..0a11711382b8 100644 --- a/mmv1/third_party/terraform/acctest/test_utils.go.tmpl +++ b/mmv1/third_party/terraform/acctest/test_utils.go.tmpl @@ -81,9 +81,13 @@ func CheckDataSourceStateMatchesResourceStateWithIgnores(dataSourceName, resourc func MuxedProviders(testName string) (func() tfprotov5.ProviderServer, error) { ctx := context.Background() + // primary is the SDKv2 implementation of the provider + // If tests are run in VCR mode, the provider will use a cached config specific to the test name + primary := GetSDKProvider(testName) + providers := []func() tfprotov5.ProviderServer{ - providerserver.NewProtocol5(NewFrameworkTestProvider(testName)), // framework provider - GetSDKProvider(testName).GRPCProvider, // sdk provider + primary.GRPCProvider, // sdk provider + providerserver.NewProtocol5(NewFrameworkTestProvider(testName, primary)), // framework provider } muxServer, err := tf5muxserver.NewMuxServer(ctx, providers...) diff --git a/mmv1/third_party/terraform/acctest/vcr_utils.go b/mmv1/third_party/terraform/acctest/vcr_utils.go index 6fe133a0c1d1..5e55ca88cb2d 100644 --- a/mmv1/third_party/terraform/acctest/vcr_utils.go +++ b/mmv1/third_party/terraform/acctest/vcr_utils.go @@ -21,7 +21,6 @@ import ( "testing" "time" - "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwprovider" tpgprovider "github.com/hashicorp/terraform-provider-google/google/provider" "github.com/hashicorp/terraform-provider-google/google/tpgresource" @@ -30,12 +29,9 @@ import ( "github.com/dnaeon/go-vcr/cassette" "github.com/dnaeon/go-vcr/recorder" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" - fwDiags "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/provider" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -53,7 +49,6 @@ var configsLock = sync.RWMutex{} var sourcesLock = sync.RWMutex{} var configs map[string]*transport_tpg.Config -var fwProviders map[string]*frameworkTestProvider var sources map[string]VcrSource @@ -203,39 +198,6 @@ func closeRecorder(t *testing.T) { delete(sources, t.Name()) sourcesLock.Unlock() } - - configsLock.RLock() - fwProvider, fwOk := fwProviders[t.Name()] - configsLock.RUnlock() - if fwOk { - // We did not cache the config if it does not use VCR - if !t.Failed() && IsVcrEnabled() { - // If a test succeeds, write new seed/yaml to files - err := fwProvider.Client.Transport.(*recorder.Recorder).Stop() - if err != nil { - t.Error(err) - } - envPath := os.Getenv("VCR_PATH") - - sourcesLock.RLock() - vcrSource, ok := sources[t.Name()] - sourcesLock.RUnlock() - if ok { - err = writeSeedToFile(vcrSource.seed, vcrSeedFile(envPath, t.Name())) - if err != nil { - t.Error(err) - } - } - } - // Clean up test config - configsLock.Lock() - delete(fwProviders, t.Name()) - configsLock.Unlock() - - sourcesLock.Lock() - delete(sources, t.Name()) - sourcesLock.Unlock() - } } func isReleaseDiffEnabled() bool { @@ -319,6 +281,11 @@ func reformConfigWithProvider(config, provider string) string { return string(resourceHeader.ReplaceAll(configBytes, providerReplacementBytes)) } +// HandleVCRConfiguration configures the recorder (github.com/dnaeon/go-vcr/recorder) used in the VCR test +// This includes: +// - Setting the recording/replaying mode +// - Determining the path to the file API interactions will be recorded to/read from +// - Determining the logic used to match requests against recorded HTTP interactions (see rec.SetMatcher) func HandleVCRConfiguration(ctx context.Context, testName string, rndTripper http.RoundTripper, pollInterval time.Duration) (time.Duration, http.RoundTripper, fwDiags.Diagnostics) { var diags fwDiags.Diagnostics var vcrMode recorder.Mode @@ -402,18 +369,18 @@ func NewVcrMatcherFunc(ctx context.Context) func(r *http.Request, i cassette.Req // test versions of the provider that will call the same configure function, only append the VCR // configuration to it. -func NewFrameworkTestProvider(testName string) *frameworkTestProvider { +func NewFrameworkTestProvider(testName string, primary *schema.Provider) *frameworkTestProvider { return &frameworkTestProvider{ FrameworkProvider: fwprovider.FrameworkProvider{ Version: "test", + Primary: primary, }, TestName: testName, } } -// frameworkTestProvider is a test version of the plugin-framework version of the provider -// that embeds FrameworkProvider whose configure function we can use -// the Configure function is overwritten in the framework_provider_test file +// frameworkTestProvider is a test version of the plugin-framework version of the provider. +// This facilitates overwriting the Configure function that's used during acceptance tests. type frameworkTestProvider struct { fwprovider.FrameworkProvider TestName string @@ -421,26 +388,13 @@ type frameworkTestProvider struct { // Configure is here to overwrite the FrameworkProvider configure function for VCR testing func (p *frameworkTestProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { - p.FrameworkProvider.Configure(ctx, req, resp) - if IsVcrEnabled() { - if resp.Diagnostics.HasError() { - return - } - - var diags fwDiags.Diagnostics - p.PollInterval, p.Client.Transport, diags = HandleVCRConfiguration(ctx, p.TestName, p.Client.Transport, p.PollInterval) - if diags.HasError() { - resp.Diagnostics.Append(diags...) - return - } - configsLock.Lock() - fwProviders[p.TestName] = p - configsLock.Unlock() - return - } else { - tflog.Debug(ctx, "VCR_PATH or VCR_MODE not set, skipping VCR") - } + // When creating the frameworkTestProvider struct we took in a pointer to the the SDK provider. + // That SDK provider was configured using `GetSDKProvider` and `getCachedConfig`, so this framework provider will also + // use a cached client for the correct test name. + // No extra logic is required here, but in future when the SDK provider is removed this function will + // need to be updated with logic similar to that in `GetSDKProvider`. + p.FrameworkProvider.Configure(ctx, req, resp) } // DataSources overrides the provider's DataSources function so that we can append test-specific data sources to the list of data sources on the provider. @@ -451,21 +405,9 @@ func (p *frameworkTestProvider) DataSources(ctx context.Context) []func() dataso return ds } -func configureApiClient(ctx context.Context, p *fwprovider.FrameworkProvider, diags *fwDiags.Diagnostics) { - var data fwmodels.ProviderModel - var d fwDiags.Diagnostics - - // Set defaults if needed - the only attribute without a default is ImpersonateServiceAccountDelegates - // this is a bit of a hack, but we'll just initialize it here so that it's been initialized at least - data.ImpersonateServiceAccountDelegates, d = types.ListValue(types.StringType, []attr.Value{}) - diags.Append(d...) - if diags.HasError() { - return - } - p.LoadAndValidateFramework(ctx, &data, "test", diags, p.Version) -} - -// GetSDKProvider gets the SDK provider with an overwritten configure function to be called by MuxedProviders +// GetSDKProvider gets the SDK provider for use in acceptance tests +// If VCR is in use, the configure function is overwritten. +// See usage in MuxedProviders func GetSDKProvider(testName string) *schema.Provider { prov := tpgprovider.Provider() diff --git a/mmv1/third_party/terraform/functions/zone_from_id.go b/mmv1/third_party/terraform/functions/zone_from_id.go index c1f3ae95eeaa..c87654af3b0a 100644 --- a/mmv1/third_party/terraform/functions/zone_from_id.go +++ b/mmv1/third_party/terraform/functions/zone_from_id.go @@ -30,7 +30,7 @@ func (f ZoneFromIdFunction) Definition(ctx context.Context, req function.Definit Parameters: []function.Parameter{ function.StringParameter{ Name: "id", - Description: "An id of a resouce, or a self link. For example, both \"projects/my-project/zones/us-central1-c/instances/my-instance\" and \"https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c/instances/my-instance\" are valid inputs", + Description: "An id of a resource, or a self link. For example, both \"projects/my-project/zones/us-central1-c/instances/my-instance\" and \"https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1-c/instances/my-instance\" are valid inputs", }, }, Return: function.StringReturn{}, diff --git a/mmv1/third_party/terraform/fwprovider/data_source_provider_config_plugin_framework.go b/mmv1/third_party/terraform/fwprovider/data_source_provider_config_plugin_framework.go index 315d2dd093fc..8df58c5c4a5b 100644 --- a/mmv1/third_party/terraform/fwprovider/data_source_provider_config_plugin_framework.go +++ b/mmv1/third_party/terraform/fwprovider/data_source_provider_config_plugin_framework.go @@ -4,20 +4,19 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. var ( _ datasource.DataSource = &GoogleProviderConfigPluginFrameworkDataSource{} _ datasource.DataSourceWithConfigure = &GoogleProviderConfigPluginFrameworkDataSource{} - _ fwresource.LocationDescriber = &GoogleProviderConfigPluginFrameworkModel{} ) func NewGoogleProviderConfigPluginFrameworkDataSource() datasource.DataSource { @@ -25,15 +24,17 @@ func NewGoogleProviderConfigPluginFrameworkDataSource() datasource.DataSource { } type GoogleProviderConfigPluginFrameworkDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } +// GoogleProviderConfigPluginFrameworkModel describes the data source and matches the schema. Its fields match those in a Config struct (google/transport/config.go) but uses a different type system. +// - In the original Config struct old SDK/Go primitives types are used, e.g. `string` +// - Here in the GoogleProviderConfigPluginFrameworkModel struct we need to use the terraform-plugin-framework/types type system, e.g. `types.String` +// - This is needed because the PF type system is 'baked into' how we define schemas. The schema will expect a nullable type. +// - See terraform-plugin-framework/datasource/schema#StringAttribute's CustomType: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework@v1.7.0/datasource/schema#StringAttribute +// - Due to the different type systems of Config versus GoogleProviderConfigPluginFrameworkModel struct, we need to convert from primitive types to terraform-plugin-framework/types when we populate +// GoogleProviderConfigPluginFrameworkModel structs with data in this data source's Read method. type GoogleProviderConfigPluginFrameworkModel struct { - // Currently this reflects the FrameworkProviderConfig struct and ProviderModel in google/fwmodels/provider_model.go - // which means it uses the plugin-framework type system where values can be explicitly Null or Unknown. - // - // As part of future muxing fixes/refactoring we'll change this struct to reflect structs used in the SDK code, and will move to - // using the SDK type system. Credentials types.String `tfsdk:"credentials"` AccessToken types.String `tfsdk:"access_token"` ImpersonateServiceAccount types.String `tfsdk:"impersonate_service_account"` @@ -53,15 +54,6 @@ type GoogleProviderConfigPluginFrameworkModel struct { TerraformAttributionLabelAdditionStrategy types.String `tfsdk:"terraform_attribution_label_addition_strategy"` } -func (m *GoogleProviderConfigPluginFrameworkModel) GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) fwresource.LocationDescription { - return fwresource.LocationDescription{ - RegionSchemaField: types.StringValue("region"), - ZoneSchemaField: types.StringValue("zone"), - ProviderRegion: providerConfig.Region, - ProviderZone: providerConfig.Zone, - } -} - func (d *GoogleProviderConfigPluginFrameworkDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_provider_config_plugin_framework" } @@ -172,11 +164,11 @@ func (d *GoogleProviderConfigPluginFrameworkDataSource) Configure(ctx context.Co return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -202,23 +194,54 @@ func (d *GoogleProviderConfigPluginFrameworkDataSource) Read(ctx context.Context } // Copy all values from the provider config into this data source + // - The 'meta' from the provider configuration process uses Go primitive types (e.g. `string`) but this data source needs to use the plugin-framework type system due to being PF-implemented + // - As a result we have to make conversions between type systems in the value assignments below + data.Credentials = types.StringValue(d.providerConfig.Credentials) + data.AccessToken = types.StringValue(d.providerConfig.AccessToken) + data.ImpersonateServiceAccount = types.StringValue(d.providerConfig.ImpersonateServiceAccount) + + delegateAttrs := make([]attr.Value, len(d.providerConfig.ImpersonateServiceAccountDelegates)) + for i, delegate := range d.providerConfig.ImpersonateServiceAccountDelegates { + delegateAttrs[i] = types.StringValue(delegate) + } + delegates, di := types.ListValue(types.StringType, delegateAttrs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.ImpersonateServiceAccountDelegates = delegates + + data.Project = types.StringValue(d.providerConfig.Project) + data.Region = types.StringValue(d.providerConfig.Region) + data.BillingProject = types.StringValue(d.providerConfig.BillingProject) + data.Zone = types.StringValue(d.providerConfig.Zone) + data.UniverseDomain = types.StringValue(d.providerConfig.UniverseDomain) + + scopeAttrs := make([]attr.Value, len(d.providerConfig.Scopes)) + for i, scope := range d.providerConfig.Scopes { + scopeAttrs[i] = types.StringValue(scope) + } + scopes, di := types.ListValue(types.StringType, scopeAttrs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.Scopes = scopes + + data.UserProjectOverride = types.BoolValue(d.providerConfig.UserProjectOverride) + data.RequestReason = types.StringValue(d.providerConfig.RequestReason) + data.RequestTimeout = types.StringValue(d.providerConfig.RequestTimeout.String()) + + lbs := make(map[string]attr.Value, len(d.providerConfig.DefaultLabels)) + for k, v := range d.providerConfig.DefaultLabels { + lbs[k] = types.StringValue(v) + } + labels, di := types.MapValueFrom(ctx, types.StringType, lbs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.DefaultLabels = labels - data.Credentials = d.providerConfig.Credentials - data.AccessToken = d.providerConfig.AccessToken - data.ImpersonateServiceAccount = d.providerConfig.ImpersonateServiceAccount - data.ImpersonateServiceAccountDelegates = d.providerConfig.ImpersonateServiceAccountDelegates - data.Project = d.providerConfig.Project - data.Region = d.providerConfig.Region - data.BillingProject = d.providerConfig.BillingProject - data.Zone = d.providerConfig.Zone - data.UniverseDomain = d.providerConfig.UniverseDomain - data.Scopes = d.providerConfig.Scopes - data.UserProjectOverride = d.providerConfig.UserProjectOverride - data.RequestReason = d.providerConfig.RequestReason - data.RequestTimeout = d.providerConfig.RequestTimeout - data.DefaultLabels = d.providerConfig.DefaultLabels - data.AddTerraformAttributionLabel = d.providerConfig.AddTerraformAttributionLabel - data.TerraformAttributionLabelAdditionStrategy = d.providerConfig.TerraformAttributionLabelAdditionStrategy + data.AddTerraformAttributionLabel = types.BoolValue(d.providerConfig.AddTerraformAttributionLabel) + data.TerraformAttributionLabelAdditionStrategy = types.StringValue(d.providerConfig.TerraformAttributionLabelAdditionStrategy) // Warn users against using this data source resp.Diagnostics.Append(diag.NewWarningDiagnostic( diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider.go.tmpl b/mmv1/third_party/terraform/fwprovider/framework_provider.go.tmpl index 60e7cc1ac23e..47db6d12ad56 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider.go.tmpl +++ b/mmv1/third_party/terraform/fwprovider/framework_provider.go.tmpl @@ -3,8 +3,11 @@ package fwprovider import ( "context" + sdk_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/provider" @@ -14,9 +17,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-google/google/fwvalidators" "github.com/hashicorp/terraform-provider-google/google/functions" "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/services/resourcemanager" "github.com/hashicorp/terraform-provider-google/version" {{- if ne $.TargetVersionName "ga" }} @@ -31,19 +34,21 @@ var ( _ provider.Provider = &FrameworkProvider{} _ provider.ProviderWithMetaSchema = &FrameworkProvider{} _ provider.ProviderWithFunctions = &FrameworkProvider{} + _ provider.ProviderWithEphemeralResources = &FrameworkProvider{} ) // New is a helper function to simplify provider server and testing implementation. -func New() provider.ProviderWithMetaSchema { +func New(primary *sdk_schema.Provider) provider.ProviderWithMetaSchema { return &FrameworkProvider{ Version: version.ProviderVersion, + Primary: primary, } } // FrameworkProvider is the provider implementation. type FrameworkProvider struct { - fwtransport.FrameworkProviderConfig Version string + Primary *sdk_schema.Provider } // Metadata returns @@ -66,6 +71,9 @@ func (p *FrameworkProvider) MetaSchema(_ context.Context, _ provider.MetaSchemaR } // Schema defines the provider-level schema for configuration data. +// See: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux +// "The schema and configuration handling must exactly match between all underlying providers of the mux server" +// This schema matches the schema implemented with SDKv2 in google/provider/provider.go func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ @@ -75,8 +83,8 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, stringvalidator.ConflictsWith(path.Expressions{ path.MatchRoot("access_token"), }...), - CredentialsValidator(), - NonEmptyStringValidator(), + fwvalidators.CredentialsValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "access_token": schema.StringAttribute{ @@ -85,13 +93,13 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, stringvalidator.ConflictsWith(path.Expressions{ path.MatchRoot("credentials"), }...), - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "impersonate_service_account": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "impersonate_service_account_delegates": schema.ListAttribute{ @@ -101,25 +109,25 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, "project": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "billing_project": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "region": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "zone": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonEmptyStringValidator(), + fwvalidators.NonEmptyStringValidator(), }, }, "scopes": schema.ListAttribute{ @@ -131,6 +139,10 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, }, "request_timeout": schema.StringAttribute{ Optional: true, + Validators: []validator.String{ + fwvalidators.NonEmptyStringValidator(), + fwvalidators.NonNegativeDurationValidator(), + }, }, "request_reason": schema.StringAttribute{ Optional: true, @@ -231,7 +243,7 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, "send_after": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - NonNegativeDurationValidator(), + fwvalidators.NonNegativeDurationValidator(), }, }, "enable_batching": schema.BoolAttribute{ @@ -259,16 +271,21 @@ func (p *FrameworkProvider) Configure(ctx context.Context, req provider.Configur return } - // Configuration values are now available. - p.LoadAndValidateFramework(ctx, &data, req.TerraformVersion, &resp.Diagnostics, p.Version) - if resp.Diagnostics.HasError() { - return - } + // Configuration values are now available. + // However we don't use them; for the plugin-framework implementation of the provider + // we take the configuration values from the SDK implementation of the provider. This avoids duplicated logic and inconsistencies in implementation. + // The trade off is that we don't benefit from the new type system that differentiates Null and Unknown values, which is especially useful for strings. + // This makes it necessary to write code that stops empty strings (etc) being passed from the Config struct to PF-implemented resources/datasources. + // E.g. GetProjectFramework treats Null and "" the same way : https://github.com/hashicorp/terraform-provider-google/blob/74c815ee4ad059453e06b84448af244d80490ec1/google/fwresource/field_helpers.go#L21-L36 + // See also, new approaches to handle this: https://github.com/GoogleCloudPlatform/magic-modules/pull/11925 + // This is how we make provider configuration info (configured clients, default project, etc) available to resources and data sources - // implemented using the plugin-framework. The resources' Configure functions receive this data in the ConfigureRequest argument. - resp.DataSourceData = &p.FrameworkProviderConfig - resp.ResourceData = &p.FrameworkProviderConfig + // implemented using the plugin-framework. The resources' Configure functions receive this data in the ConfigureRequest argument. + meta := p.Primary.Meta().(*transport_tpg.Config) + resp.DataSourceData = meta + resp.ResourceData = meta + resp.EphemeralResourceData = meta } @@ -301,3 +318,13 @@ func (p *FrameworkProvider) Functions(_ context.Context) []func() function.Funct functions.NewZoneFromIdFunction, } } + +// EphemeralResources defines the resources that are of ephemeral type implemented in the provider. +func (p *FrameworkProvider) EphemeralResources(_ context.Context) []func() ephemeral.EphemeralResource { + return []func() ephemeral.EphemeralResource{ + resourcemanager.GoogleEphemeralServiceAccountAccessToken, + resourcemanager.GoogleEphemeralServiceAccountIdToken, + resourcemanager.GoogleEphemeralServiceAccountJwt, + resourcemanager.GoogleEphemeralServiceAccountKey, + } +} diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_access_token_test.go.tmpl b/mmv1/third_party/terraform/fwprovider/framework_provider_access_token_test.go.tmpl index ccc304e8cad1..6794da8e9d1d 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_access_token_test.go.tmpl +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_access_token_test.go.tmpl @@ -191,7 +191,7 @@ credentials = "%s" Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "access_token", accessToken), // not set as ENV not used - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "credentials"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "credentials", ""), ), }, { @@ -204,7 +204,7 @@ credentials = "%s" Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "credentials", credentials), // not set, as ENV not used - resource.TestCheckNoResourceAttr("data.google_provider_config_sdk.default", "access_token"), + resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "access_token", ""), ), ExpectError: regexp.MustCompile("JSON credentials are not valid"), }, @@ -258,7 +258,7 @@ func testAccFwProvider_access_token_authInUse(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Assert provider is using access_token argument for auth, not credentials resource.TestCheckResourceAttrSet("data.google_provider_config_plugin_framework.default", "access_token"), - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "credentials"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "credentials", ""), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_add_terraform_attribution_label_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_add_terraform_attribution_label_test.go index d9eeb07ed5a2..e99a00e8a4f3 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_add_terraform_attribution_label_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_add_terraform_attribution_label_test.go @@ -13,8 +13,8 @@ import ( func TestAccFwProvider_add_terraform_attribution_label(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "when add_terraform_attribution_label is set in the config, the value is set in the provider meta data": testAccFwProvider_add_terraform_attribution_label_configUsed, - "when add_terraform_attribution_label is unset in the config, the default value 'true' is NOT set on the provider meta data": testAccFwProvider_add_terraform_attribution_label_defaultValue, + "when add_terraform_attribution_label is set in the config, the value is set in the provider meta data": testAccFwProvider_add_terraform_attribution_label_configUsed, + "when add_terraform_attribution_label is unset in the config, the default value 'true' is set on the provider meta data": testAccFwProvider_add_terraform_attribution_label_defaultValue, } for name, tc := range testCases { @@ -71,7 +71,7 @@ func testAccFwProvider_add_terraform_attribution_label_defaultValue(t *testing.T { Config: testAccFwProvider_add_terraform_attribution_label_inEnvsOnly(context), Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "add_terraform_attribution_label"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "add_terraform_attribution_label", "true"), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_billing_project_test.go.tmpl b/mmv1/third_party/terraform/fwprovider/framework_provider_billing_project_test.go.tmpl index 37fcb7137fa7..a5d6f428d0b4 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_billing_project_test.go.tmpl +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_billing_project_test.go.tmpl @@ -111,7 +111,7 @@ func testAccFwProvider_billing_project_precedenceOrderEnvironmentVariables(t *te }, Config: testAccFwProvider_billing_project_inEnvsOnly(context), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "billing_project"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "billing_project", ""), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_internal_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_internal_test.go index 8c4eff047541..539498d423b3 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_internal_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_internal_test.go @@ -5,8 +5,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-provider-google/google/fwprovider" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func TestFrameworkProvider_impl(t *testing.T) { - var _ provider.ProviderWithMetaSchema = fwprovider.New() + primary := &schema.Provider{} + var _ provider.ProviderWithMetaSchema = fwprovider.New(primary) } diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_project_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_project_test.go index e7b41bcfc2cf..1f4c23eebc4f 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_project_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_project_test.go @@ -87,9 +87,7 @@ func testAccFwProvider_project_precedenceOrderEnvironmentVariables(t *testing.T) }, Config: testAccFwProvider_projectInEnvsOnly(), Check: resource.ComposeTestCheckFunc( - // Differing behavior between SDK and PF; the attribute is NOT found here. - // This reflects the different type systems used in the SDKv2 and the plugin-framework - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "project"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "project", ""), ), }, { diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_request_reason_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_request_reason_test.go index c2845d24b382..5431ee81c218 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_request_reason_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_request_reason_test.go @@ -18,7 +18,7 @@ func TestAccFwProvider_request_reason(t *testing.T) { // Schema-level validation // TODO: https://github.com/hashicorp/terraform-provider-google/issues/19643 - "when request_reason is set to an empty string in the config the value is not ignored, and there isn't any validation about this that raises an error": testAccFwProvider_request_reason_emptyStringValidation, + "when request_reason is set to an empty string in the config the value IS ignored, allowing environment values to be used": testAccFwProvider_request_reason_emptyStringValidation, // Usage // We cannot test the impact of this field in an acc test, as it sets the X-Goog-Request-Reason value for audit logging purposes in GCP @@ -116,7 +116,7 @@ func testAccFwProvider_request_reason_emptyStringValidation(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Currently the PF provider uses empty strings, instead of providing validation feedback to users // See: https://github.com/hashicorp/terraform-provider-google/issues/19643 - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_reason", emptyString), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_reason", envReason), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_request_timeout_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_request_timeout_test.go index aa22b6a496f5..d17f26034676 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_request_timeout_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_request_timeout_test.go @@ -14,8 +14,8 @@ import ( func TestAccFwProvider_request_timeout(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "a default value of 120s is used when there are no user inputs": testAccFwProvider_request_timeout_providerDefault, - "request_timeout can be set in config in different formats, are NOT normalized to full-length format": testAccFwProvider_request_timeout_setInConfig, + "a default value of 0s is used when there are no user inputs": testAccFwProvider_request_timeout_providerDefault, + "request_timeout can be set in config in different formats, are normalized to full-length format": testAccFwProvider_request_timeout_setInConfig, //no ENVs to test // Schema-level validation @@ -40,7 +40,7 @@ func TestAccFwProvider_request_timeout(t *testing.T) { func testAccFwProvider_request_timeout_providerDefault(t *testing.T) { acctest.SkipIfVcr(t) // Test doesn't interact with API - defaultValue := "120s" + defaultValue := "0s" acctest.VcrTest(t, resource.TestCase{ // No PreCheck for checking ENVs @@ -62,9 +62,8 @@ func testAccFwProvider_request_timeout_setInConfig(t *testing.T) { providerTimeout1 := "3m0s" providerTimeout2 := "3m" - // In the SDK version of the test expectedValue = "3m0s" only - expectedValue1 := "3m0s" - expectedValue2 := "3m" + // All inputs are normalised to this + expectedValue := "3m0s" context1 := map[string]interface{}{ "request_timeout": providerTimeout1, @@ -80,13 +79,13 @@ func testAccFwProvider_request_timeout_setInConfig(t *testing.T) { { Config: testAccFwProvider_request_timeout_inProviderBlock(context1), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue1), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue), ), }, { Config: testAccFwProvider_request_timeout_inProviderBlock(context2), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue2), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go b/mmv1/third_party/terraform/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go index 921edce47d38..b45a9d68bee4 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go @@ -13,8 +13,8 @@ import ( func TestAccFwProvider_terraform_attribution_label_addition_strategy(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "config sets terraform_attribution_label_addition_strategy values": testAccFwProvider_terraform_attribution_label_addition_strategy_configUsed, - "when terraform_attribution_label_addition_strategy is unset in the config, the default value'CREATION_ONLY' is NOT set in the provider meta data": testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValue, + "config sets terraform_attribution_label_addition_strategy values": testAccFwProvider_terraform_attribution_label_addition_strategy_configUsed, + "when terraform_attribution_label_addition_strategy is unset in the config, the default value 'CREATION_ONLY' is set in the provider meta data": testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValue, } for name, tc := range testCases { @@ -71,7 +71,7 @@ func testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValu { Config: testAccFwProvider_terraform_attribution_label_addition_strategy_inEnvsOnly(context), Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "terraform_attribution_label_addition_strategy"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "terraform_attribution_label_addition_strategy", "CREATION_ONLY"), ), }, }, diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_test.go.tmpl b/mmv1/third_party/terraform/fwprovider/framework_provider_test.go.tmpl index 0a910cabedaf..fe8a1d3677dc 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_test.go.tmpl +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_test.go.tmpl @@ -11,14 +11,11 @@ import ( "github.com/hashicorp/terraform-provider-google/google/acctest" "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) func TestAccFrameworkProviderMeta_setModuleName(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() moduleName := "my-module" @@ -63,46 +60,22 @@ func TestAccFrameworkProviderBasePath_setInvalidBasePath(t *testing.T) { } func TestAccFrameworkProviderBasePath_setBasePath(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, CheckDestroy: testAccCheckDNSManagedZoneDestroyProducerFramework(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Steps: []resource.TestStep{ { - ExternalProviders: map[string]resource.ExternalProvider{ - "google": { - VersionConstraint: "4.58.0", - Source: "hashicorp/google{{- if ne $.TargetVersionName "ga" -}}-{{$.TargetVersionName}}{{- end }}", - }, - }, - Config: testAccFrameworkProviderBasePath_setBasePath("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), - }, - { - ExternalProviders: map[string]resource.ExternalProvider{ - "google": { - VersionConstraint: "4.58.0", - Source: "hashicorp/google{{- if ne $.TargetVersionName "ga" -}}-{{$.TargetVersionName}}{{- end }}", - }, - }, - ResourceName: "google_dns_managed_zone.foo", - ImportState: true, - ImportStateVerify: true, - }, - { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Config: testAccFrameworkProviderBasePath_setBasePath("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), }, { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ResourceName: "google_dns_managed_zone.foo", ImportState: true, ImportStateVerify: true, }, { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Config: testAccFrameworkProviderBasePath_setBasePathstep3("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), }, }, @@ -221,21 +194,28 @@ func testAccCheckDNSManagedZoneDestroyProducerFramework(t *testing.T) func(s *te continue } - p := acctest.GetFwTestProvider(t) + config := acctest.GoogleProviderConfig(t) - url, err := fwresource.ReplaceVarsForFrameworkTest(&p.FrameworkProvider.FrameworkProviderConfig, rs, "{{"{{"}}DNSBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/managedZones/{{"{{"}}name{{"}}"}}") + url, err := fwresource.ReplaceVarsForFrameworkTest(config, rs, "{{"{{"}}DNSBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/managedZones/{{"{{"}}name{{"}}"}}") if err != nil { return err } billingProject := "" - if !p.BillingProject.IsNull() && p.BillingProject.String() != "" { - billingProject = p.BillingProject.String() + if config.BillingProject != "" { + billingProject = config.BillingProject } - _, diags := fwtransport.SendFrameworkRequest(&p.FrameworkProvider.FrameworkProviderConfig, "GET", billingProject, url, p.UserAgent, nil) - if !diags.HasError() { + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + + if err == nil { return fmt.Errorf("DNSManagedZone still exists at %s", url) } } diff --git a/mmv1/third_party/terraform/fwprovider/framework_provider_user_project_override_test.go.tmpl b/mmv1/third_party/terraform/fwprovider/framework_provider_user_project_override_test.go.tmpl index 5576186241a8..1bdf6a8ea3b2 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_provider_user_project_override_test.go.tmpl +++ b/mmv1/third_party/terraform/fwprovider/framework_provider_user_project_override_test.go.tmpl @@ -95,7 +95,7 @@ func testAccFwProvider_user_project_override_precedenceOrderEnvironmentVariables }, Config: testAccFwProvider_user_project_overrideInEnvsOnly(context), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "user_project_override"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "user_project_override", "false"), ), }, { diff --git a/mmv1/third_party/terraform/fwprovider/framework_validators_test.go b/mmv1/third_party/terraform/fwprovider/framework_validators_test.go deleted file mode 100644 index 6462f3af43b8..000000000000 --- a/mmv1/third_party/terraform/fwprovider/framework_validators_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package fwprovider_test - -import ( - "context" - "testing" - - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework/types" - - "github.com/hashicorp/terraform-provider-google/google/acctest" - "github.com/hashicorp/terraform-provider-google/google/fwprovider" - - transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" -) - -func TestFrameworkProvider_CredentialsValidator(t *testing.T) { - cases := map[string]struct { - ConfigValue types.String - ExpectedWarningCount int - ExpectedErrorCount int - }{ - "configuring credentials as a path to a credentials JSON file is valid": { - ConfigValue: types.StringValue(transport_tpg.TestFakeCredentialsPath), // Path to a test fixture - }, - "configuring credentials as a path to a non-existant file is NOT valid": { - ConfigValue: types.StringValue("./this/path/doesnt/exist.json"), // Doesn't exist - ExpectedErrorCount: 1, - }, - "configuring credentials as a credentials JSON string is valid": { - ConfigValue: types.StringValue(acctest.GenerateFakeCredentialsJson("CredentialsValidator")), - }, - "configuring credentials as an empty string is not valid": { - ConfigValue: types.StringValue(""), - ExpectedErrorCount: 1, - }, - "leaving credentials unconfigured is valid": { - ConfigValue: types.StringNull(), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - // Arrange - req := validator.StringRequest{ - ConfigValue: tc.ConfigValue, - } - - resp := validator.StringResponse{ - Diagnostics: diag.Diagnostics{}, - } - - cv := fwprovider.CredentialsValidator() - - // Act - cv.ValidateString(context.Background(), req, &resp) - - // Assert - if resp.Diagnostics.WarningsCount() > tc.ExpectedWarningCount { - t.Errorf("Expected %d warnings, got %d", tc.ExpectedWarningCount, resp.Diagnostics.WarningsCount()) - } - if resp.Diagnostics.ErrorsCount() > tc.ExpectedErrorCount { - t.Errorf("Expected %d errors, got %d", tc.ExpectedErrorCount, resp.Diagnostics.ErrorsCount()) - } - }) - } -} diff --git a/mmv1/third_party/terraform/fwresource/field_helpers.go b/mmv1/third_party/terraform/fwresource/field_helpers.go index cfc09b5337a7..54788d8346e7 100644 --- a/mmv1/third_party/terraform/fwresource/field_helpers.go +++ b/mmv1/third_party/terraform/fwresource/field_helpers.go @@ -9,8 +9,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // GetProject reads the "project" field from the given resource and falls @@ -69,7 +69,7 @@ func ParseProjectFieldValueFramework(resourceType, fieldValue, projectSchemaFiel // This function isn't a test of transport.go; instead, it is used as an alternative // to ReplaceVars inside tests. -func ReplaceVarsForFrameworkTest(prov *fwtransport.FrameworkProviderConfig, rs *terraform.ResourceState, linkTmpl string) (string, error) { +func ReplaceVarsForFrameworkTest(prov *transport_tpg.Config, rs *terraform.ResourceState, linkTmpl string) (string, error) { re := regexp.MustCompile("{{([[:word:]]+)}}") var project, region, zone string diff --git a/mmv1/third_party/terraform/fwresource/framework_location.go b/mmv1/third_party/terraform/fwresource/framework_location.go index 609ab65b98b1..565aa9089420 100644 --- a/mmv1/third_party/terraform/fwresource/framework_location.go +++ b/mmv1/third_party/terraform/fwresource/framework_location.go @@ -5,12 +5,12 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) type LocationDescriber interface { - GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) LocationDescription + GetLocationDescription(providerConfig *transport_tpg.Config) LocationDescription } type LocationDescription struct { diff --git a/mmv1/third_party/terraform/fwtransport/framework_config.go.tmpl b/mmv1/third_party/terraform/fwtransport/framework_config.go.tmpl deleted file mode 100644 index 25e715009913..000000000000 --- a/mmv1/third_party/terraform/fwtransport/framework_config.go.tmpl +++ /dev/null @@ -1,740 +0,0 @@ -package fwtransport - -import ( - "context" - "fmt" - "net/http" - "os" - "regexp" - "strconv" - "time" - - "golang.org/x/oauth2" - googleoauth "golang.org/x/oauth2/google" - - "google.golang.org/api/option" - "google.golang.org/api/transport" - "google.golang.org/grpc" - - "github.com/hashicorp/go-cleanhttp" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-log/tflog" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" - - "github.com/hashicorp/terraform-provider-google/google/fwmodels" - transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" - "github.com/hashicorp/terraform-provider-google/google/verify" - - grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" - "github.com/sirupsen/logrus" -) - -type FrameworkProviderConfig struct { - // Temporary, as we'll replace use of FrameworkProviderConfig with transport_tpg.Config soon - // transport_tpg.Config has a the fields below, hence these changes are needed - Credentials types.String - AccessToken types.String - ImpersonateServiceAccount types.String - ImpersonateServiceAccountDelegates types.List - RequestReason types.String - RequestTimeout types.String - AddTerraformAttributionLabel types.Bool - TerraformAttributionLabelAdditionStrategy types.String - // End temporary - - BillingProject types.String - Client *http.Client - Context context.Context - gRPCLoggingOptions []option.ClientOption - PollInterval time.Duration - Project types.String - Region types.String - Zone types.String - RequestBatcherIam *transport_tpg.RequestBatcher - RequestBatcherServiceUsage *transport_tpg.RequestBatcher - Scopes types.List - TokenSource oauth2.TokenSource - UniverseDomain types.String - UserAgent string - UserProjectOverride types.Bool - DefaultLabels types.Map - - // paths for client setup - {{- range $product := $.Products }} - {{ $product.Name }}BasePath string - {{- end }} -} - -// LoadAndValidateFramework handles the bulk of configuring the provider -// it is pulled out so that we can manually call this from our testing provider as well -func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context, data *fwmodels.ProviderModel, tfVersion string, diags *diag.Diagnostics, providerversion string) { - - // Set defaults if needed - p.HandleDefaults(ctx, data, diags) - if diags.HasError() { - return - } - - p.Context = ctx - - // Handle User Agent string - p.UserAgent = CompileUserAgentString(ctx, "terraform-provider-google{{- if ne $.TargetVersionName "ga" -}}-{{$.TargetVersionName}}{{- end }}", tfVersion, providerversion) - // opt in extension for adding to the User-Agent header - if ext := os.Getenv("GOOGLE_TERRAFORM_USERAGENT_EXTENSION"); ext != "" { - ua := p.UserAgent - p.UserAgent = fmt.Sprintf("%s %s", ua, ext) - } - - // Set up client configuration - p.SetupClient(ctx, *data, diags) - if diags.HasError() { - return - } - - // gRPC Logging setup - p.SetupGrpcLogging() - - // Handle Batching Config - batchingConfig := GetBatchingConfig(ctx, data.Batching, diags) - if diags.HasError() { - return - } - - // Setup Base Paths for clients - // Generated products - {{- range $product := $.Products }} - p.{{ $product.Name }}BasePath = data.{{ $product.Name }}CustomEndpoint.ValueString() - {{- end }} - - // Temporary - p.Credentials = data.Credentials - p.AccessToken = data.AccessToken - p.ImpersonateServiceAccount = data.ImpersonateServiceAccount - p.ImpersonateServiceAccountDelegates = data.ImpersonateServiceAccountDelegates - p.RequestReason = data.RequestReason - p.RequestTimeout = data.RequestTimeout - p.AddTerraformAttributionLabel = data.AddTerraformAttributionLabel - p.TerraformAttributionLabelAdditionStrategy = data.TerraformAttributionLabelAdditionStrategy - // End temporary - - // Copy values from the ProviderModel struct containing data about the provider configuration (present only when responsing to ConfigureProvider rpc calls) - // to the FrameworkProviderConfig struct that will be passed and available to all resources/data sources - p.Context = ctx - p.BillingProject = data.BillingProject - p.DefaultLabels = data.DefaultLabels - p.Project = data.Project - p.Region = GetRegionFromRegionSelfLink(data.Region) - p.Scopes = data.Scopes - p.Zone = data.Zone - p.UserProjectOverride = data.UserProjectOverride - p.PollInterval = 10 * time.Second - p.UniverseDomain = data.UniverseDomain - p.RequestBatcherServiceUsage = transport_tpg.NewRequestBatcher("Service Usage", ctx, batchingConfig) - p.RequestBatcherIam = transport_tpg.NewRequestBatcher("IAM", ctx, batchingConfig) -} - -// HandleDefaults will handle all the defaults necessary in the provider -func (p *FrameworkProviderConfig) HandleDefaults(ctx context.Context, data *fwmodels.ProviderModel, diags *diag.Diagnostics) { - if (data.AccessToken.IsNull() || data.AccessToken.IsUnknown()) && (data.Credentials.IsNull() || data.Credentials.IsUnknown()) { - credentials := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CREDENTIALS", - "GOOGLE_CLOUD_KEYFILE_JSON", - "GCLOUD_KEYFILE_JSON", - }, nil) - - if credentials != nil { - data.Credentials = types.StringValue(credentials.(string)) - } - - accessToken := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_OAUTH_ACCESS_TOKEN", - }, nil) - - if accessToken != nil { - data.AccessToken = types.StringValue(accessToken.(string)) - } - } - - if (data.ImpersonateServiceAccount.IsNull() || data.ImpersonateServiceAccount.IsUnknown()) && os.Getenv("GOOGLE_IMPERSONATE_SERVICE_ACCOUNT") != "" { - data.ImpersonateServiceAccount = types.StringValue(os.Getenv("GOOGLE_IMPERSONATE_SERVICE_ACCOUNT")) - } - - if data.Project.IsNull() || data.Project.IsUnknown() { - project := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_PROJECT", - "GOOGLE_CLOUD_PROJECT", - "GCLOUD_PROJECT", - "CLOUDSDK_CORE_PROJECT", - }, nil) - if project != nil { - data.Project = types.StringValue(project.(string)) - } - } - - if data.BillingProject.IsNull() && os.Getenv("GOOGLE_BILLING_PROJECT") != "" { - data.BillingProject = types.StringValue(os.Getenv("GOOGLE_BILLING_PROJECT")) - } - - if data.Region.IsNull() || data.Region.IsUnknown() { - region := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_REGION", - "GCLOUD_REGION", - "CLOUDSDK_COMPUTE_REGION", - }, nil) - - if region != nil { - data.Region = types.StringValue(region.(string)) - } - } - - if data.Zone.IsNull() || data.Zone.IsUnknown() { - zone := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_ZONE", - "GCLOUD_ZONE", - "CLOUDSDK_COMPUTE_ZONE", - }, nil) - - if zone != nil { - data.Zone = types.StringValue(zone.(string)) - } - } - - if len(data.Scopes.Elements()) == 0 { - var d diag.Diagnostics - data.Scopes, d = types.ListValueFrom(ctx, types.StringType, transport_tpg.DefaultClientScopes) - diags.Append(d...) - if diags.HasError() { - return - } - } - - if !data.Batching.IsNull() && !data.Batching.IsUnknown() { - var pbConfigs []fwmodels.ProviderBatching - d := data.Batching.ElementsAs(ctx, &pbConfigs, true) - diags.Append(d...) - if diags.HasError() { - return - } - - if pbConfigs[0].SendAfter.IsNull() || pbConfigs[0].SendAfter.IsUnknown() { - pbConfigs[0].SendAfter = types.StringValue("10s") - } - - if pbConfigs[0].EnableBatching.IsNull() || pbConfigs[0].EnableBatching.IsUnknown() { - pbConfigs[0].EnableBatching = types.BoolValue(true) - } - - data.Batching, d = types.ListValueFrom(ctx, types.ObjectType{}.WithAttributeTypes(fwmodels.ProviderBatchingAttributes), pbConfigs) - } - - if (data.UserProjectOverride.IsNull() || data.UserProjectOverride.IsUnknown()) && os.Getenv("USER_PROJECT_OVERRIDE") != "" { - override, err := strconv.ParseBool(os.Getenv("USER_PROJECT_OVERRIDE")) - if err != nil { - diags.AddError( - "error parsing environment variable `USER_PROJECT_OVERRIDE` into bool", err.Error()) - } - data.UserProjectOverride = types.BoolValue(override) - } - - if (data.RequestReason.IsNull() || data.RequestReason.IsUnknown()) && os.Getenv("CLOUDSDK_CORE_REQUEST_REASON") != "" { - data.RequestReason = types.StringValue(os.Getenv("CLOUDSDK_CORE_REQUEST_REASON")) - } - - if data.RequestTimeout.IsNull() || data.RequestTimeout.IsUnknown() { - data.RequestTimeout = types.StringValue("120s") - } - - // Generated Products -{{- range $product := $.Products }} - if data.{{ $product.Name }}CustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_{{ upper (underscore $product.Name) }}_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.{{ $product.Name }}BasePathKey]) - if customEndpoint != nil { - data.{{ $product.Name }}CustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } -{{- end }} - - // Handwritten Products / Versioned / Atypical Entries - if data.CloudBillingCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CLOUD_BILLING_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths["cloud_billing_custom_endpoint"]) - if customEndpoint != nil { - data.CloudBillingCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.ComposerCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_COMPOSER_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ComposerBasePathKey]) - if customEndpoint != nil { - data.ComposerCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.ContainerCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CONTAINER_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ContainerBasePathKey]) - if customEndpoint != nil { - data.ContainerCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.DataflowCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_DATAFLOW_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.DataflowBasePathKey]) - if customEndpoint != nil { - data.DataflowCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.IamCredentialsCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_IAM_CREDENTIALS_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.IamCredentialsBasePathKey]) - if customEndpoint != nil { - data.IamCredentialsCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.ResourceManagerV3CustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_RESOURCE_MANAGER_V3_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ResourceManagerV3BasePathKey]) - if customEndpoint != nil { - data.ResourceManagerV3CustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - -{{ if ne $.TargetVersionName `ga` -}} - if data.RuntimeConfigCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_RUNTIMECONFIG_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.RuntimeConfigBasePathKey]) - if customEndpoint != nil { - data.RuntimeConfigCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } -{{- end }} - - if data.IAMCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_IAM_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.IAMBasePathKey]) - if customEndpoint != nil { - data.IAMCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.ServiceNetworkingCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_SERVICE_NETWORKING_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ServiceNetworkingBasePathKey]) - if customEndpoint != nil { - data.ServiceNetworkingCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.TagsLocationCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_TAGS_LOCATION_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.TagsLocationBasePathKey]) - if customEndpoint != nil { - data.TagsLocationCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - // dcl - if data.ContainerAwsCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CONTAINERAWS_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ContainerAwsBasePathKey]) - if customEndpoint != nil { - data.ContainerAwsCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.ContainerAzureCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CONTAINERAZURE_CUSTOM_ENDPOINT", - }, transport_tpg.DefaultBasePaths[transport_tpg.ContainerAzureBasePathKey]) - if customEndpoint != nil { - data.ContainerAzureCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - // DCL generated defaults - if data.ApikeysCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_APIKEYS_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.ApikeysCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.AssuredWorkloadsCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_ASSURED_WORKLOADS_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.AssuredWorkloadsCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.CloudBuildWorkerPoolCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CLOUD_BUILD_WORKER_POOL_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.CloudBuildWorkerPoolCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.CloudResourceManagerCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_CLOUD_RESOURCE_MANAGER_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.CloudResourceManagerCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.DataplexCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_DATAPLEX_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.DataplexCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.EventarcCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_EVENTARC_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.EventarcCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.FirebaserulesCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_FIREBASERULES_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.FirebaserulesCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.NetworkConnectivityCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_NETWORK_CONNECTIVITY_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.NetworkConnectivityCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } - - if data.RecaptchaEnterpriseCustomEndpoint.IsNull() { - customEndpoint := transport_tpg.MultiEnvDefault([]string{ - "GOOGLE_RECAPTCHA_ENTERPRISE_CUSTOM_ENDPOINT", - }, "") - if customEndpoint != nil { - data.RecaptchaEnterpriseCustomEndpoint = types.StringValue(customEndpoint.(string)) - } - } -} - -func (p *FrameworkProviderConfig) SetupClient(ctx context.Context, data fwmodels.ProviderModel, diags *diag.Diagnostics) { - tokenSource := GetTokenSource(ctx, data, false, diags) - if diags.HasError() { - return - } - - cleanCtx := context.WithValue(ctx, oauth2.HTTPClient, cleanhttp.DefaultClient()) - - // 1. MTLS TRANSPORT/CLIENT - sets up proper auth headers - client, _, err := transport.NewHTTPClient(cleanCtx, option.WithTokenSource(tokenSource)) - if err != nil { - diags.AddError("error creating new http client", err.Error()) - return - } - - // Userinfo is fetched before request logging is enabled to reduce additional noise. - p.logGoogleIdentities(ctx, data, diags) - if diags.HasError() { - return - } - - // 2. Logging Transport - ensure we log HTTP requests to GCP APIs. - loggingTransport := logging.NewTransport("Google", client.Transport) - - // 3. Retry Transport - retries common temporary errors - // Keep order for wrapping logging so we log each retried request as well. - // This value should be used if needed to create shallow copies with additional retry predicates. - // See ClientWithAdditionalRetries - retryTransport := transport_tpg.NewTransportWithDefaultRetries(loggingTransport) - - // 4. Header Transport - outer wrapper to inject additional headers we want to apply - // before making requests - headerTransport := transport_tpg.NewTransportWithHeaders(retryTransport) - if !data.RequestReason.IsNull() { - headerTransport.Set("X-Goog-Request-Reason", data.RequestReason.ValueString()) - } - - // Ensure $userProject is set for all HTTP requests using the client if specified by the provider config - // See https://cloud.google.com/apis/docs/system-parameters - if data.UserProjectOverride.ValueBool() && !data.BillingProject.IsNull() { - headerTransport.Set("X-Goog-User-Project", data.BillingProject.ValueString()) - } - - // Set final transport value. - client.Transport = headerTransport - - // This timeout is a timeout per HTTP request, not per logical operation. - timeout, err := time.ParseDuration(data.RequestTimeout.ValueString()) - if err != nil { - diags.AddError("error parsing request timeout", err.Error()) - } - client.Timeout = timeout - - p.TokenSource = tokenSource - p.Client = client -} - -func (p *FrameworkProviderConfig) SetupGrpcLogging() { - logger := logrus.StandardLogger() - - logrus.SetLevel(logrus.DebugLevel) - logrus.SetFormatter(&transport_tpg.Formatter{ - TimestampFormat: "2006/01/02 15:04:05", - LogFormat: "%time% [%lvl%] %msg% \n", - }) - - alwaysLoggingDeciderClient := func(ctx context.Context, fullMethodName string) bool { return true } - grpc_logrus.ReplaceGrpcLogger(logrus.NewEntry(logger)) - - p.gRPCLoggingOptions = append( - p.gRPCLoggingOptions, option.WithGRPCDialOption(grpc.WithUnaryInterceptor( - grpc_logrus.PayloadUnaryClientInterceptor(logrus.NewEntry(logger), alwaysLoggingDeciderClient))), - option.WithGRPCDialOption(grpc.WithStreamInterceptor( - grpc_logrus.PayloadStreamClientInterceptor(logrus.NewEntry(logger), alwaysLoggingDeciderClient))), - ) -} - -func (p *FrameworkProviderConfig) logGoogleIdentities(ctx context.Context, data fwmodels.ProviderModel, diags *diag.Diagnostics) { - // GetCurrentUserEmailFramework doesn't pass an error back from logGoogleIdentities, so we want - // a separate diagnostics here - var d diag.Diagnostics - - if data.ImpersonateServiceAccount.IsNull() || data.ImpersonateServiceAccount.IsUnknown() { - - tokenSource := GetTokenSource(ctx, data, true, diags) - if diags.HasError() { - return - } - - p.Client = oauth2.NewClient(ctx, tokenSource) // p.Client isn't initialised fully when this code is called. - - email := GetCurrentUserEmailFramework(p, p.UserAgent, &d) - if d.HasError() { - tflog.Info(ctx, "error retrieving userinfo for your provider credentials. have you enabled the 'https://www.googleapis.com/auth/userinfo.email' scope?") - } - - tflog.Info(ctx, fmt.Sprintf("Terraform is using this identity: %s", email)) - return - } - - // Drop Impersonated ClientOption from OAuth2 TokenSource to infer original identity - tokenSource := GetTokenSource(ctx, data, true, diags) - if diags.HasError() { - return - } - - p.Client = oauth2.NewClient(ctx, tokenSource) // p.Client isn't initialised fully when this code is called. - email := GetCurrentUserEmailFramework(p, p.UserAgent, &d) - if d.HasError() { - tflog.Info(ctx, "error retrieving userinfo for your provider credentials. have you enabled the 'https://www.googleapis.com/auth/userinfo.email' scope?") - } - - tflog.Info(ctx, fmt.Sprintf("Terraform is configured with service account impersonation, original identity: %s, impersonated identity: %s", email, data.ImpersonateServiceAccount.ValueString())) - - // Add the Impersonated ClientOption back in to the OAuth2 TokenSource - tokenSource = GetTokenSource(ctx, data, false, diags) - if diags.HasError() { - return - } - - p.Client = oauth2.NewClient(ctx, tokenSource) // p.Client isn't initialised fully when this code is called. - - return -} - -// Configuration helpers - -// GetTokenSource gets token source based on the Google Credentials configured. -// If initialCredentialsOnly is true, don't follow the impersonation settings and return the initial set of creds. -func GetTokenSource(ctx context.Context, data fwmodels.ProviderModel, initialCredentialsOnly bool, diags *diag.Diagnostics) oauth2.TokenSource { - creds := GetCredentials(ctx, data, initialCredentialsOnly, diags) - - return creds.TokenSource -} - -// GetCredentials gets credentials with a given scope (clientScopes). -// If initialCredentialsOnly is true, don't follow the impersonation -// settings and return the initial set of creds instead. -func GetCredentials(ctx context.Context, data fwmodels.ProviderModel, initialCredentialsOnly bool, diags *diag.Diagnostics) googleoauth.Credentials { - var clientScopes []string - var delegates []string - - if !data.Scopes.IsNull() && !data.Scopes.IsUnknown() { - d := data.Scopes.ElementsAs(ctx, &clientScopes, false) - diags.Append(d...) - if diags.HasError() { - return googleoauth.Credentials{} - } - } - - if !data.ImpersonateServiceAccountDelegates.IsNull() && !data.ImpersonateServiceAccountDelegates.IsUnknown() { - d := data.ImpersonateServiceAccountDelegates.ElementsAs(ctx, &delegates, false) - diags.Append(d...) - if diags.HasError() { - return googleoauth.Credentials{} - } - } - - if !data.AccessToken.IsNull() && !data.AccessToken.IsUnknown() { - contents, _, err := verify.PathOrContents(data.AccessToken.ValueString()) - if err != nil { - diags.AddError("error loading access token", err.Error()) - return googleoauth.Credentials{} - } - - token := &oauth2.Token{AccessToken: contents} - if !data.ImpersonateServiceAccount.IsNull() && !initialCredentialsOnly { - opts := []option.ClientOption{option.WithTokenSource(oauth2.StaticTokenSource(token)), option.ImpersonateCredentials(data.ImpersonateServiceAccount.ValueString(), delegates...), option.WithScopes(clientScopes...)} - creds, err := transport.Creds(context.TODO(), opts...) - if err != nil { - diags.AddError("error impersonating credentials", err.Error()) - return googleoauth.Credentials{} - } - return *creds - } - - tflog.Info(ctx, "Authenticating using configured Google JSON 'access_token'...") - tflog.Info(ctx, fmt.Sprintf(" -- Scopes: %s", clientScopes)) - return googleoauth.Credentials{ - TokenSource: transport_tpg.StaticTokenSource{oauth2.StaticTokenSource(token)}, - } - } - - if !data.Credentials.IsNull() && !data.Credentials.IsUnknown() { - contents, _, err := verify.PathOrContents(data.Credentials.ValueString()) - if err != nil { - diags.AddError(fmt.Sprintf("error loading credentials: %s", err), err.Error()) - return googleoauth.Credentials{} - } - if len(contents) == 0 { - diags.AddError("error loading credentials", "provided credentials are empty") - return googleoauth.Credentials{} - } - - if !data.ImpersonateServiceAccount.IsNull() && !initialCredentialsOnly { - opts := []option.ClientOption{option.WithCredentialsJSON([]byte(contents)), option.ImpersonateCredentials(data.ImpersonateServiceAccount.ValueString(), delegates...), option.WithScopes(clientScopes...)} - creds, err := transport.Creds(context.TODO(), opts...) - if err != nil { - diags.AddError("error impersonating credentials", err.Error()) - return googleoauth.Credentials{} - } - return *creds - } - - creds, err := transport.Creds(ctx, option.WithCredentialsJSON([]byte(contents)), option.WithScopes(clientScopes...)) - if err != nil { - diags.AddError("unable to parse credentials", err.Error()) - return googleoauth.Credentials{} - } - - tflog.Info(ctx, "Authenticating using configured Google JSON 'credentials'...") - tflog.Info(ctx, fmt.Sprintf(" -- Scopes: %s", clientScopes)) - return *creds - } - - if !data.ImpersonateServiceAccount.IsNull() && !initialCredentialsOnly { - opts := option.ImpersonateCredentials(data.ImpersonateServiceAccount.ValueString(), delegates...) - creds, err := transport.Creds(context.TODO(), opts, option.WithScopes(clientScopes...)) - if err != nil { - diags.AddError("error impersonating credentials", err.Error()) - return googleoauth.Credentials{} - } - - return *creds - } - - tflog.Info(ctx, "Authenticating using DefaultClient...") - tflog.Info(ctx, fmt.Sprintf(" -- Scopes: %s", clientScopes)) - creds, err := transport.Creds(context.Background(), option.WithScopes(clientScopes...)) - if err != nil { - diags.AddError(fmt.Sprintf("Attempted to load application default credentials since neither `credentials` nor `access_token` was set in the provider block. "+ - "No credentials loaded. To use your gcloud credentials, run 'gcloud auth application-default login'"), err.Error()) - return googleoauth.Credentials{} - } - - return *creds -} - -// GetBatchingConfig returns the batching config object given the -// provider configuration set for batching -func GetBatchingConfig(ctx context.Context, data types.List, diags *diag.Diagnostics) *transport_tpg.BatchingConfig { - bc := &transport_tpg.BatchingConfig{ - SendAfter: time.Second * transport_tpg.DefaultBatchSendIntervalSec, - EnableBatching: true, - } - - // Handle if entire batching block is null/unknown - if data.IsNull() || data.IsUnknown() { - return bc - } - - var pbConfigs []fwmodels.ProviderBatching - d := data.ElementsAs(ctx, &pbConfigs, true) - diags.Append(d...) - if diags.HasError() { - return bc - } - - sendAfter, err := time.ParseDuration(pbConfigs[0].SendAfter.ValueString()) - if err != nil { - diags.AddError("error parsing send after time duration", err.Error()) - return bc - } - - bc.SendAfter = sendAfter - - if !pbConfigs[0].EnableBatching.IsNull() { - bc.EnableBatching = pbConfigs[0].EnableBatching.ValueBool() - } - - return bc -} - -func GetRegionFromRegionSelfLink(selfLink basetypes.StringValue) basetypes.StringValue { - re := regexp.MustCompile("/compute/[a-zA-Z0-9]*/projects/[a-zA-Z0-9-]*/regions/([a-zA-Z0-9-]*)") - value := selfLink.String() - switch { - case re.MatchString(value): - if res := re.FindStringSubmatch(value); len(res) == 2 && res[1] != "" { - region := res[1] - return types.StringValue(region) - } - } - return selfLink -} diff --git a/mmv1/third_party/terraform/fwtransport/framework_config_test.go.tmpl b/mmv1/third_party/terraform/fwtransport/framework_config_test.go.tmpl deleted file mode 100644 index d4e34eae78bb..000000000000 --- a/mmv1/third_party/terraform/fwtransport/framework_config_test.go.tmpl +++ /dev/null @@ -1,1585 +0,0 @@ -package fwtransport_test - -import ( - "context" - "testing" - - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-provider-google/google/acctest" - "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" - transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" -) - -func TestFrameworkProvider_LoadAndValidateFramework_project(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under test experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue // Sometimes the value is mutated, and no longer matches the original value we supply - ExpectedConfigStructValue basetypes.StringValue // Sometimes the value in config struct differs from what is in the data model - ExpectError bool - }{ - "project value set in the provider schema is not overridden by environment variables": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringValue("project-from-config"), - }, - EnvVariables: map[string]string{ - "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", - "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", - "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", - "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-config"), - ExpectedConfigStructValue: types.StringValue("project-from-config"), - }, - "project value can be set by environment variable: GOOGLE_PROJECT is used first": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringNull(), // unset - }, - EnvVariables: map[string]string{ - "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", - "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", - "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", - "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-GOOGLE_PROJECT"), - ExpectedConfigStructValue: types.StringValue("project-from-GOOGLE_PROJECT"), - }, - "project value can be set by environment variable: GOOGLE_CLOUD_PROJECT is used second": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringNull(), // unset - }, - EnvVariables: map[string]string{ - // GOOGLE_PROJECT unset - "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", - "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", - "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-GOOGLE_CLOUD_PROJECT"), - ExpectedConfigStructValue: types.StringValue("project-from-GOOGLE_CLOUD_PROJECT"), - }, - "project value can be set by environment variable: GCLOUD_PROJECT is used third": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringNull(), // unset - }, - EnvVariables: map[string]string{ - // GOOGLE_PROJECT unset - // GOOGLE_CLOUD_PROJECT unset - "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", - "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-GCLOUD_PROJECT"), - ExpectedConfigStructValue: types.StringValue("project-from-GCLOUD_PROJECT"), - }, - "project value can be set by environment variable: CLOUDSDK_CORE_PROJECT is used fourth": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringNull(), // unset - }, - EnvVariables: map[string]string{ - // GOOGLE_PROJECT unset - // GOOGLE_CLOUD_PROJECT unset - // GCLOUD_PROJECT unset - "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-CLOUDSDK_CORE_PROJECT"), - ExpectedConfigStructValue: types.StringValue("project-from-CLOUDSDK_CORE_PROJECT"), - }, - "when no project values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringNull(), // unset - }, - ExpectedDataModelValue: types.StringNull(), - ExpectedConfigStructValue: types.StringNull(), - }, - // Handling empty strings in config - "when project is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - "when project is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - // Handling unknown values - "when project is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - Project: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", - }, - ExpectedDataModelValue: types.StringValue("project-from-GOOGLE_PROJECT"), - ExpectedConfigStructValue: types.StringValue("project-from-GOOGLE_PROJECT"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.Project.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want project in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.Project.String()) - } - // Checking the value passed to the config structs - if !p.Project.Equal(tc.ExpectedConfigStructValue) { - t.Fatalf("want project in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.Project.String()) - } - }) - } -} - -// NOTE: these tests can't run in Cloud Build due to ADC locating credentials despite `GOOGLE_APPLICATION_CREDENTIALS` being unset -// See https://cloud.google.com/docs/authentication/application-default-credentials#search_order -// Also, when running these tests locally you need to run `gcloud auth application-default revoke` to ensure your machine isn't supplying ADCs -// func TestFrameworkProvider_LoadAndValidateFramework_credentials_unknown(t *testing.T) { -// // This test case is kept separate from other credentials tests, as it requires comparing -// // error messages returned by two different error states: -// // - When credentials = Null -// // - When credentials = Unknown - -// t.Run("the same error is returned whether credentials is set as a null or unknown value (and access_token isn't set)", func(t *testing.T) { -// // Arrange -// acctest.UnsetTestProviderConfigEnvs(t) - -// ctx := context.Background() -// tfVersion := "foobar" -// providerversion := "999" - -// impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - -// // Null data and error collection -// diagsNull := diag.Diagnostics{} -// dataNull := fwmodels.ProviderModel{ -// Credentials: types.StringNull(), -// } -// dataNull.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - -// // Unknown data and error collection -// diagsUnknown := diag.Diagnostics{} -// dataUnknown := fwmodels.ProviderModel{ -// Credentials: types.StringUnknown(), -// } -// dataUnknown.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - -// pNull := fwtransport.FrameworkProviderConfig{} -// pUnknown := fwtransport.FrameworkProviderConfig{} - -// // Act -// pNull.LoadAndValidateFramework(ctx, &dataNull, tfVersion, &diagsNull, providerversion) -// pUnknown.LoadAndValidateFramework(ctx, &dataUnknown, tfVersion, &diagsUnknown, providerversion) - -// // Assert -// if !diagsNull.HasError() { -// t.Fatalf("expect errors when credentials is null, but [%d] errors occurred", diagsNull.ErrorsCount()) -// } -// if !diagsUnknown.HasError() { -// t.Fatalf("expect errors when credentials is unknown, but [%d] errors occurred", diagsUnknown.ErrorsCount()) -// } - -// errNull := diagsNull.Errors() -// errUnknown := diagsUnknown.Errors() -// for i := 0; i < len(errNull); i++ { -// if errNull[i] != errUnknown[i] { -// t.Fatalf("expect errors to be the same for null and unknown credentials values, instead got \nnull=`%s` \nunknown=%s", errNull[i], errUnknown[i]) -// } -// } -// }) -// } - -func TestFrameworkProvider_LoadAndValidateFramework_billingProject(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under test experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - ExpectedConfigStructValue basetypes.StringValue - ExpectError bool - }{ - "billing_project value set in the provider schema is not overridden by environment variables": { - ConfigValues: fwmodels.ProviderModel{ - BillingProject: types.StringValue("billing-project-from-config"), - }, - EnvVariables: map[string]string{ - "GOOGLE_BILLING_PROJECT": "billing-project-from-env", - }, - ExpectedDataModelValue: types.StringValue("billing-project-from-config"), - ExpectedConfigStructValue: types.StringValue("billing-project-from-config"), - }, - "billing_project can be set by environment variable, when no value supplied via the config": { - ConfigValues: fwmodels.ProviderModel{ - BillingProject: types.StringNull(), - }, - EnvVariables: map[string]string{ - "GOOGLE_BILLING_PROJECT": "billing-project-from-env", - }, - ExpectedDataModelValue: types.StringValue("billing-project-from-env"), - ExpectedConfigStructValue: types.StringValue("billing-project-from-env"), - }, - "when no billing_project values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - BillingProject: types.StringNull(), - }, - ExpectedDataModelValue: types.StringNull(), - ExpectedConfigStructValue: types.StringNull(), - }, - // Handling empty strings in config - "when billing_project is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - BillingProject: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - "when billing_project is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - BillingProject: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_BILLING_PROJECT": "billing-project-from-env", - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.BillingProject.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want billing_project in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.BillingProject.String()) - } - // Checking the value passed to the config structs - if !p.BillingProject.Equal(tc.ExpectedConfigStructValue) { - t.Fatalf("want billing_project in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.BillingProject.String()) - } - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_region(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under test experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - ExpectedConfigStructValue basetypes.StringValue - ExpectError bool - }{ - "region value set in the provider config is not overridden by ENVs": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringValue("region-from-config"), - }, - EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", - }, - ExpectedDataModelValue: types.StringValue("region-from-config"), - ExpectedConfigStructValue: types.StringValue("region-from-config"), - }, - "region values can be supplied as a self link": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1"), - }, - ExpectedDataModelValue: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1"), - ExpectedConfigStructValue: types.StringValue("us-central1"), - }, - "region value can be set by environment variable: GOOGLE_REGION is used": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringNull(), - }, - EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", - }, - ExpectedDataModelValue: types.StringValue("region-from-env"), - ExpectedConfigStructValue: types.StringValue("region-from-env"), - }, - "when no region values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringNull(), - }, - ExpectedDataModelValue: types.StringNull(), - ExpectedConfigStructValue: types.StringNull(), - }, - // Handling empty strings in config - "when region is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - "when region is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - // Handling unknown values - "when region is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - Region: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "GOOGLE_REGION": "region-from-env", - }, - ExpectedDataModelValue: types.StringValue("region-from-env"), - ExpectedConfigStructValue: types.StringValue("region-from-env"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.Region.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want region in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.Region.String()) - } - // Checking the value passed to the config structs - if !p.Region.Equal(tc.ExpectedConfigStructValue) { - t.Fatalf("want region in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.Region.String()) - } - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_zone(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under test experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - ExpectedConfigStructValue basetypes.StringValue - ExpectError bool - }{ - "zone value set in the provider config is not overridden by ENVs": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringValue("zone-from-config"), - }, - EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-env", - }, - ExpectedDataModelValue: types.StringValue("zone-from-config"), - ExpectedConfigStructValue: types.StringValue("zone-from-config"), - }, - "does not shorten zone values when provided as a self link": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1"), - }, - ExpectedDataModelValue: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1"), - ExpectedConfigStructValue: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1"), // Value is not shortened from URI to name - }, - "when multiple zone environment variables are provided, `GOOGLE_ZONE` is used first": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringNull(), - }, - EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-GOOGLE_ZONE", - "GCLOUD_ZONE": "zone-from-GCLOUD_ZONE", - "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", - }, - ExpectedDataModelValue: types.StringValue("zone-from-GOOGLE_ZONE"), - ExpectedConfigStructValue: types.StringValue("zone-from-GOOGLE_ZONE"), - }, - "when multiple zone environment variables are provided, `GCLOUD_ZONE` is used second": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringNull(), - }, - EnvVariables: map[string]string{ - // GOOGLE_ZONE unset - "GCLOUD_ZONE": "zone-from-GCLOUD_ZONE", - "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", - }, - ExpectedDataModelValue: types.StringValue("zone-from-GCLOUD_ZONE"), - ExpectedConfigStructValue: types.StringValue("zone-from-GCLOUD_ZONE"), - }, - "when multiple zone environment variables are provided, `CLOUDSDK_COMPUTE_ZONE` is used third": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringNull(), - }, - EnvVariables: map[string]string{ - // GOOGLE_ZONE unset - // GCLOUD_ZONE unset - "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", - }, - ExpectedDataModelValue: types.StringValue("zone-from-CLOUDSDK_COMPUTE_ZONE"), - ExpectedConfigStructValue: types.StringValue("zone-from-CLOUDSDK_COMPUTE_ZONE"), - }, - "when no zone values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringNull(), - }, - ExpectedDataModelValue: types.StringNull(), - ExpectedConfigStructValue: types.StringNull(), - }, - // Handling empty strings in config - "when zone is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - "when zone is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-env", - }, - ExpectedDataModelValue: types.StringValue(""), - ExpectedConfigStructValue: types.StringValue(""), - }, - // Handling unknown values - "when zone is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - Zone: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "GOOGLE_ZONE": "zone-from-env", - }, - ExpectedDataModelValue: types.StringValue("zone-from-env"), - ExpectedConfigStructValue: types.StringValue("zone-from-env"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.Zone.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want zone in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.Zone.String()) - } - // Checking the value passed to the config structs - if !p.Zone.Equal(tc.ExpectedConfigStructValue) { - t.Fatalf("want zone in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.Zone.String()) - } - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_accessToken(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue // Sometimes the value is mutated, and no longer matches the original value we supply - // ExpectedConfigStructValue not used here, as credentials info isn't stored in the config struct - ExpectError bool - }{ - "access_token configured in the provider can be invalid without resulting in errors": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringValue("This is not a valid token string"), - }, - ExpectedDataModelValue: types.StringValue("This is not a valid token string"), - }, - "access_token set in the provider config is not overridden by environment variables": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringValue("value-from-config"), - }, - EnvVariables: map[string]string{ - "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-env", - }, - ExpectedDataModelValue: types.StringValue("value-from-config"), - }, - "when access_token is unset in the config, the GOOGLE_OAUTH_ACCESS_TOKEN environment variable is used": { - EnvVariables: map[string]string{ - "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", - }, - ExpectedDataModelValue: types.StringValue("value-from-GOOGLE_OAUTH_ACCESS_TOKEN"), - }, - "when no access_token values are provided via config or environment variables there's no error (as long as credentials supplied in its absence)": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringNull(), - Credentials: types.StringValue(transport_tpg.TestFakeCredentialsPath), - }, - ExpectedDataModelValue: types.StringNull(), - }, - // Handling empty strings in config - "when access_token is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - }, - "when access_token is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", - }, - ExpectedDataModelValue: types.StringValue(""), - }, - // Handling unknown values - "when access_token is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - AccessToken: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", - }, - ExpectedDataModelValue: types.StringValue("value-from-GOOGLE_OAUTH_ACCESS_TOKEN"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.AccessToken.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want project in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.AccessToken.String()) - } - // fwtransport.FrameworkProviderConfig does not store the credentials info, so test does not make assertions on config struct - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_userProjectOverride(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.BoolValue - ExpectedConfigStructValue basetypes.BoolValue - ExpectError bool - }{ - "user_project_override value set in the provider schema is not overridden by ENVs": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolValue(false), - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "true", - }, - ExpectedDataModelValue: types.BoolValue(false), - ExpectedConfigStructValue: types.BoolValue(false), - }, - "user_project_override can be set by environment variable: value = true": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolNull(), // not set - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "true", - }, - ExpectedDataModelValue: types.BoolValue(true), - ExpectedConfigStructValue: types.BoolValue(true), - }, - "user_project_override can be set by environment variable: value = false": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolNull(), // not set - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "false", - }, - ExpectedDataModelValue: types.BoolValue(false), - ExpectedConfigStructValue: types.BoolValue(false), - }, - "user_project_override can be set by environment variable: value = 1": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolNull(), // not set - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "1", - }, - ExpectedDataModelValue: types.BoolValue(true), - ExpectedConfigStructValue: types.BoolValue(true), - }, - "user_project_override can be set by environment variable: value = 0": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolNull(), // not set - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "0", - }, - ExpectedDataModelValue: types.BoolValue(false), - ExpectedConfigStructValue: types.BoolValue(false), - }, - "setting user_project_override using a non-boolean environment variables results in an error": { - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "I'm not a boolean", - }, - ExpectError: true, - }, - "when no user_project_override values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolNull(), // not set - }, - ExpectedDataModelValue: types.BoolNull(), - ExpectedConfigStructValue: types.BoolNull(), - }, - // Handling unknown values - "when user_project_override is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - UserProjectOverride: types.BoolUnknown(), - }, - EnvVariables: map[string]string{ - "USER_PROJECT_OVERRIDE": "true", - }, - ExpectedDataModelValue: types.BoolValue(true), - ExpectedConfigStructValue: types.BoolValue(true), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.UserProjectOverride.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want user_project_override in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.UserProjectOverride.String()) - } - // Checking the value passed to the config structs - if !p.UserProjectOverride.Equal(tc.ExpectedConfigStructValue) { - t.Fatalf("want user_project_override in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.UserProjectOverride.String()) - } - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_impersonateServiceAccount(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - ExpectedConfigStructValue basetypes.StringValue - ExpectError bool - }{ - "impersonate_service_account value set in the provider schema is not overridden by environment variables": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringValue("value-from-config@example.com"), - }, - EnvVariables: map[string]string{ - "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", - }, - ExpectedDataModelValue: types.StringValue("value-from-config@example.com"), - }, - "impersonate_service_account value can be set by environment variable": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringNull(), // not set - }, - EnvVariables: map[string]string{ - "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", - }, - ExpectedDataModelValue: types.StringValue("value-from-env@example.com"), - }, - "when no values are provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringNull(), // not set - }, - ExpectedDataModelValue: types.StringNull(), - }, - // Handling empty strings in config - "when impersonate_service_account is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - }, - "when impersonate_service_account is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", - }, - ExpectedDataModelValue: types.StringValue(""), - }, - // Handling unknown values - "when impersonate_service_account is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - ImpersonateServiceAccount: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", - }, - ExpectedDataModelValue: types.StringValue("value-from-env@example.com"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.ImpersonateServiceAccount.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want impersonate_service_account in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.ImpersonateServiceAccount.String()) - } - // fwtransport.FrameworkProviderConfig does not store impersonate_service_account info, so test does not make assertions on config struct - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_impersonateServiceAccountDelegates(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - - cases := map[string]struct { - // It's not easy to define basetypes.ListValue values directly in test case, so instead - // pass values into test function to control construction of basetypes.ListValue there. - SetAsNull bool - SetAsUnknown bool - ImpersonateServiceAccountDelegatesValue []string - EnvVariables map[string]string - - ExpectedNull bool - ExpectedUnknown bool - ExpectedDataModelValue []string - ExpectError bool - }{ - "impersonate_service_account_delegates value can be set in the provider schema": { - ImpersonateServiceAccountDelegatesValue: []string{ - "projects/-/serviceAccounts/my-service-account-1@example.iam.gserviceaccount.com", - "projects/-/serviceAccounts/my-service-account-2@example.iam.gserviceaccount.com", - }, - ExpectedDataModelValue: []string{ - "projects/-/serviceAccounts/my-service-account-1@example.iam.gserviceaccount.com", - "projects/-/serviceAccounts/my-service-account-2@example.iam.gserviceaccount.com", - }, - }, - // Note: no environment variables can be used for impersonate_service_account_delegates - "when no impersonate_service_account_delegates value is provided via config, the field remains unset without error": { - SetAsNull: true, // not setting impersonate_service_account_delegates - ExpectedNull: true, - }, - // Handling empty values in config - "when impersonate_service_account_delegates is set as an empty array, that value isn't ignored": { - ImpersonateServiceAccountDelegatesValue: []string{}, - ExpectedDataModelValue: []string{}, - }, - // Handling unknown values - "when impersonate_service_account_delegates is an unknown value, the provider treats it as if it's unset, without error": { - SetAsUnknown: true, - ExpectedUnknown: true, - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := fwmodels.ProviderModel{} - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - // Set ImpersonateServiceAccountDelegates depending on test case - if !tc.SetAsNull && !tc.SetAsUnknown { - isad, _ := types.ListValueFrom(ctx, types.StringType, tc.ImpersonateServiceAccountDelegatesValue) - data.ImpersonateServiceAccountDelegates = isad - } - if tc.SetAsNull { - data.ImpersonateServiceAccountDelegates = types.ListNull(types.StringType) - } - if tc.SetAsUnknown { - data.ImpersonateServiceAccountDelegates = types.ListUnknown(types.StringType) - } - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - var expected attr.Value - if !tc.ExpectedNull && !tc.ExpectedUnknown { - expected, _ = types.ListValueFrom(ctx, types.StringType, tc.ExpectedDataModelValue) - } - if tc.ExpectedNull { - expected = types.ListNull(types.StringType) - } - if tc.ExpectedUnknown { - expected = types.ListUnknown(types.StringType) - } - if !data.ImpersonateServiceAccountDelegates.Equal(expected) { - t.Fatalf("want impersonate_service_account in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", expected, data.ImpersonateServiceAccountDelegates.String()) - } - // fwtransport.FrameworkProviderConfig does not store impersonate_service_account info, so test does not make assertions on config struct - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_scopes(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ScopesValue []string - EnvVariables map[string]string - ExpectedDataModelValue []string - ExpectedConfigStructValue []string - SetAsNull bool - SetAsUnknown bool - ExpectError bool - }{ - "scopes are set in the provider config as a list": { - ScopesValue: []string{"fizz", "buzz", "baz"}, - ExpectedDataModelValue: []string{"fizz", "buzz", "baz"}, - ExpectedConfigStructValue: []string{"fizz", "buzz", "baz"}, - }, - "scopes can be left unset in the provider config without any issues, and a default value is used": { - SetAsNull: true, - ExpectedDataModelValue: transport_tpg.DefaultClientScopes, - ExpectedConfigStructValue: transport_tpg.DefaultClientScopes, - }, - // Handling empty values in config - "scopes set as an empty list the field is treated as if it's unset and a default value is used without errors": { - ScopesValue: []string{}, - ExpectedDataModelValue: transport_tpg.DefaultClientScopes, - ExpectedConfigStructValue: transport_tpg.DefaultClientScopes, - }, - // Handling unknown values - "when scopes is an unknown value, the provider treats it as if it's unset and a default value is used without errors": { - SetAsUnknown: true, - ExpectedDataModelValue: transport_tpg.DefaultClientScopes, - ExpectedConfigStructValue: transport_tpg.DefaultClientScopes, - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := fwmodels.ProviderModel{} - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - // Set ImpersonateServiceAccountDelegates depending on test case - if !tc.SetAsNull && !tc.SetAsUnknown { - s, _ := types.ListValueFrom(ctx, types.StringType, tc.ScopesValue) - data.Scopes = s - } - if tc.SetAsNull { - data.Scopes = types.ListNull(types.StringType) - } - if tc.SetAsUnknown { - data.Scopes = types.ListUnknown(types.StringType) - } - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - expectedDm, _ := types.ListValueFrom(ctx, types.StringType, tc.ExpectedDataModelValue) - if !data.Scopes.Equal(expectedDm) { - t.Fatalf("want project in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.Scopes.String()) - } - // Checking the value passed to the config structs - expectedFpc, _ := types.ListValueFrom(ctx, types.StringType, tc.ExpectedConfigStructValue) - if !p.Scopes.Equal(expectedFpc) { - t.Fatalf("want project in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.Scopes.String()) - } - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_requestReason(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - // ExpectedConfigStructValue not used here, as credentials info isn't stored in the config struct - ExpectError bool - }{ - "when request_reason is unset in the config, environment variable CLOUDSDK_CORE_REQUEST_REASON is used": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringNull(), - }, - EnvVariables: map[string]string{ - "CLOUDSDK_CORE_REQUEST_REASON": "foo", - }, - ExpectedDataModelValue: types.StringValue("foo"), - }, - "request_reason set in the config is not overridden by environment variables": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringValue("value-from-config"), - }, - EnvVariables: map[string]string{ - "CLOUDSDK_CORE_REQUEST_REASON": "value-from-env", - }, - ExpectedDataModelValue: types.StringValue("value-from-config"), - }, - "when no request_reason is provided via config or environment variables, the field remains unset without error": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringNull(), - }, - ExpectedDataModelValue: types.StringNull(), - }, - // Handling empty strings in config - "when request_reason is set as an empty string, the empty string is not ignored in favor of an environment variable": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringValue(""), - }, - EnvVariables: map[string]string{ - "CLOUDSDK_CORE_REQUEST_REASON": "foo", - }, - ExpectedDataModelValue: types.StringValue(""), - }, - "when request_reason is set as an empty string the empty string is used and not ignored": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringValue(""), - }, - ExpectedDataModelValue: types.StringValue(""), - }, - // Handling unknown values - "when request_reason is an unknown value, the provider treats it as if it's unset and uses an environment variable instead": { - ConfigValues: fwmodels.ProviderModel{ - RequestReason: types.StringUnknown(), - }, - EnvVariables: map[string]string{ - "CLOUDSDK_CORE_REQUEST_REASON": "foo", - }, - ExpectedDataModelValue: types.StringValue("foo"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.RequestReason.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want request_reason in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.RequestReason.String()) - } - // fwtransport.FrameworkProviderConfig does not store the request reason info, so test does not make assertions on config struct - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_requestTimeout(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - ConfigValues fwmodels.ProviderModel - EnvVariables map[string]string - ExpectedDataModelValue basetypes.StringValue - // ExpectedConfigStructValue not used here, as credentials info isn't stored in the config struct - ExpectError bool - }{ - "if a valid request_timeout is configured in the provider, no error will occur": { - ConfigValues: fwmodels.ProviderModel{ - RequestTimeout: types.StringValue("10s"), - }, - ExpectedDataModelValue: types.StringValue("10s"), - }, - "if an invalid request_timeout is configured in the provider, an error will occur": { - ConfigValues: fwmodels.ProviderModel{ - RequestTimeout: types.StringValue("timeout"), - }, - ExpectError: true, - }, - "when request_timeout is set as an empty string, the empty string isn't ignored and an error will occur": { - ConfigValues: fwmodels.ProviderModel{ - RequestTimeout: types.StringValue(""), - }, - ExpectError: true, - }, - // In the SDK version of the provider config code, this scenario results in a value of "0s" - // instead of "120s", but the final 'effective' value is also "120s" - // See : https://github.com/hashicorp/terraform-provider-google/blob/09cb850ee64bcd78e4457df70905530c1ed75f19/google/transport/config.go#L1228-L1233 - "when request_timeout is unset in the config, the default value is 120s.": { - ConfigValues: fwmodels.ProviderModel{ - RequestTimeout: types.StringNull(), - }, - ExpectedDataModelValue: types.StringValue("120s"), - }, - // Handling unknown values - "when request_timeout is an unknown value, the provider treats it as if it's unset and uses the default value 120s": { - ConfigValues: fwmodels.ProviderModel{ - RequestTimeout: types.StringUnknown(), - }, - ExpectedDataModelValue: types.StringValue("120s"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := tc.ConfigValues - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s : %s", num, err.Summary(), err.Detail()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.RequestTimeout.Equal(tc.ExpectedDataModelValue) { - t.Fatalf("want request_timeout in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.RequestTimeout.String()) - } - // fwtransport.FrameworkProviderConfig does not store the request timeout info, so test does not make assertions on config struct - }) - } -} - -func TestFrameworkProvider_LoadAndValidateFramework_batching(t *testing.T) { - - // Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value - // this is to stop the code under tests experiencing errors, and could be addressed in future refactoring. - // - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test - // - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯ - - cases := map[string]struct { - // It's not easy to create the value of Batching in the test case, so these inputs are used in the test function - SetBatchingAsNull bool - SetBatchingAsUnknown bool - EnableBatchingValue basetypes.BoolValue - SendAfterValue basetypes.StringValue - - EnvVariables map[string]string - - ExpectBatchingNull bool - ExpectBatchingUnknown bool - ExpectEnableBatchingValue basetypes.BoolValue - ExpectSendAfterValue basetypes.StringValue - ExpectError bool - }{ - "batching can be configured with values for enable_batching and send_after": { - EnableBatchingValue: types.BoolValue(true), - SendAfterValue: types.StringValue("45s"), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("45s"), - }, - "if batching is an empty block, it will set the default values for enable_batching and send_after": { - // In this test, we try to create a list containing only null values - EnableBatchingValue: types.BoolNull(), - SendAfterValue: types.StringNull(), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("10s"), - }, - "when batching is configured with only enable_batching, send_after will be set to a default value": { - EnableBatchingValue: types.BoolValue(true), - SendAfterValue: types.StringNull(), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("10s"), - }, - "when batching is configured with only send_after, enable_batching will be set to a default value": { - EnableBatchingValue: types.BoolNull(), - SendAfterValue: types.StringValue("45s"), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("45s"), - }, - "when the whole batching block is a null value, the provider provides default values for send_after and enable_batching": { - SetBatchingAsNull: true, - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("3s"), - }, - // Handling unknown values - "when batching is an unknown value, the provider treats it as if it's unset (align to SDK behaviour)": { - SetBatchingAsUnknown: true, - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("3s"), - }, - "when batching is configured with send_after as an unknown value, send_after will be set to a default value": { - EnableBatchingValue: types.BoolValue(true), - SendAfterValue: types.StringUnknown(), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("10s"), - }, - "when batching is configured with enable_batching as an unknown value, enable_batching will be set to a default value": { - EnableBatchingValue: types.BoolUnknown(), - SendAfterValue: types.StringValue("45s"), - ExpectEnableBatchingValue: types.BoolValue(true), - ExpectSendAfterValue: types.StringValue("45s"), - }, - // Error states - "when batching is configured with send_after as an empty string, the empty string is not ignored and results in an error": { - EnableBatchingValue: types.BoolValue(true), - SendAfterValue: types.StringValue(""), - ExpectError: true, - }, - "if batching is configured with send_after as an invalid value, there's an error": { - SendAfterValue: types.StringValue("invalid value"), - ExpectError: true, - }, - "if batching is configured with send_after as number value without seconds (s), there's an error": { - SendAfterValue: types.StringValue("123"), - ExpectError: true, - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - // Arrange - acctest.UnsetTestProviderConfigEnvs(t) - acctest.SetupTestEnvs(t, tc.EnvVariables) - - ctx := context.Background() - tfVersion := "foobar" - providerversion := "999" - diags := diag.Diagnostics{} - - data := fwmodels.ProviderModel{} - data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath) - impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list - data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates - - // TODO(SarahFrench) - this code will change when batching is reworked - // See https://github.com/GoogleCloudPlatform/magic-modules/pull/7668 - if !tc.SetBatchingAsNull && !tc.SetBatchingAsUnknown { - b, _ := types.ObjectValue( - map[string]attr.Type{ - "enable_batching": types.BoolType, - "send_after": types.StringType, - }, - map[string]attr.Value{ - "enable_batching": tc.EnableBatchingValue, - "send_after": tc.SendAfterValue, - }, - ) - batching, _ := types.ListValue(types.ObjectType{}.WithAttributeTypes(fwmodels.ProviderBatchingAttributes), []attr.Value{b}) - data.Batching = batching - } - if tc.SetBatchingAsNull { - data.Batching = types.ListNull(types.ObjectType{}.WithAttributeTypes(fwmodels.ProviderBatchingAttributes)) - } - if tc.SetBatchingAsUnknown { - data.Batching = types.ListUnknown(types.ObjectType{}.WithAttributeTypes(fwmodels.ProviderBatchingAttributes)) - } - - p := fwtransport.FrameworkProviderConfig{} - - // Act - p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion) - - // Assert - if diags.HasError() && tc.ExpectError { - return - } - if diags.HasError() && !tc.ExpectError { - for i, err := range diags.Errors() { - num := i + 1 - t.Logf("unexpected error #%d : %s", num, err.Summary()) - } - t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount()) - } - // Checking mutation of the data model - if !data.Batching.IsNull() && tc.ExpectBatchingNull { - t.Fatalf("want batching in the `fwmodels.ProviderModel` struct to be null, but got the value `%s`", data.Batching.String()) - } - if !data.Batching.IsUnknown() && tc.ExpectBatchingUnknown { - t.Fatalf("want batching in the `fwmodels.ProviderModel` struct to be unknown, but got the value `%s`", data.Batching.String()) - } - - // The code doesn't mutate values in the fwmodels.ProviderModel struct if the whole batching block is null/unknown, - // so run these checks below only if we're not setting the whole batching block is null/unknown - if !tc.SetBatchingAsNull && !tc.SetBatchingAsUnknown { - var pbConfigs []fwmodels.ProviderBatching - _ = data.Batching.ElementsAs(ctx, &pbConfigs, true) - if !pbConfigs[0].EnableBatching.Equal(tc.ExpectEnableBatchingValue) { - t.Fatalf("want batching.enable_batching in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectEnableBatchingValue.String(), pbConfigs[0].EnableBatching.String()) - } - if !pbConfigs[0].SendAfter.Equal(tc.ExpectSendAfterValue) { - t.Fatalf("want batching.send_after in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectSendAfterValue.String(), pbConfigs[0].SendAfter.String()) - } - } - - // Check how the batching block's values are used to configure other parts of the `FrameworkProviderConfig` struct - // - RequestBatcherServiceUsage - // - RequestBatcherIam - if p.RequestBatcherServiceUsage.BatchingConfig.EnableBatching != tc.ExpectEnableBatchingValue.ValueBool() { - t.Fatalf("want batching.enable_batching to be `%s`, but got the value `%v`", tc.ExpectEnableBatchingValue.String(), p.RequestBatcherServiceUsage.BatchingConfig.EnableBatching) - } - if !types.StringValue(p.RequestBatcherServiceUsage.BatchingConfig.SendAfter.String()).Equal(tc.ExpectSendAfterValue) { - t.Fatalf("want batching.send_after to be `%s`, but got the value `%s`", tc.ExpectSendAfterValue.String(), p.RequestBatcherServiceUsage.BatchingConfig.SendAfter.String()) - } - if p.RequestBatcherIam.BatchingConfig.EnableBatching != tc.ExpectEnableBatchingValue.ValueBool() { - t.Fatalf("want batching.enable_batching to be `%s`, but got the value `%v`", tc.ExpectEnableBatchingValue.String(), p.RequestBatcherIam.BatchingConfig.EnableBatching) - } - if !types.StringValue(p.RequestBatcherIam.BatchingConfig.SendAfter.String()).Equal(tc.ExpectSendAfterValue) { - t.Fatalf("want batching.send_after to be `%s`, but got the value `%s`", tc.ExpectSendAfterValue.String(), p.RequestBatcherIam.BatchingConfig.SendAfter.String()) - } - }) - } -} - -func TestGetRegionFromRegionSelfLink(t *testing.T) { - cases := map[string]struct { - Input basetypes.StringValue - ExpectedOutput basetypes.StringValue - }{ - "A short region name is returned unchanged": { - Input: types.StringValue("us-central1"), - ExpectedOutput: types.StringValue("us-central1"), - }, - "A selflink is shortened to a region name": { - Input: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1"), - ExpectedOutput: types.StringValue("us-central1"), - }, - "Logic is specific to region selflinks; zone selflinks are not shortened": { - Input: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/asia-east1-a"), - ExpectedOutput: types.StringValue("https://www.googleapis.com/compute/v1/projects/my-project/zones/asia-east1-a"), - }, - } - - for tn, tc := range cases { - t.Run(tn, func(t *testing.T) { - - region := fwtransport.GetRegionFromRegionSelfLink(tc.Input) - - if region != tc.ExpectedOutput { - t.Fatalf("want %s, got %s", region, tc.ExpectedOutput) - } - }) - } -} diff --git a/mmv1/third_party/terraform/fwtransport/framework_provider_clients.go.tmpl b/mmv1/third_party/terraform/fwtransport/framework_provider_clients.go.tmpl deleted file mode 100644 index 1001fa557202..000000000000 --- a/mmv1/third_party/terraform/fwtransport/framework_provider_clients.go.tmpl +++ /dev/null @@ -1,55 +0,0 @@ -package fwtransport - -import ( - "fmt" - "strings" - - "google.golang.org/api/dns/v1" -{{- if ne $.TargetVersionName "ga" }} - firebase "google.golang.org/api/firebase/v1beta1" -{{- end }} - "google.golang.org/api/option" - - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-log/tflog" - transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" -) - -// Methods to create new services from config -// Some base paths below need the version and possibly more of the path -// set on them. The client libraries are inconsistent about which values they need; -// while most only want the host URL, some older ones also want the version and some -// of those "projects" as well. You can find out if this is required by looking at -// the basePath value in the client library file. - -func (p *FrameworkProviderConfig) NewDnsClient(userAgent string, diags *diag.Diagnostics) *dns.Service { - dnsClientBasePath := transport_tpg.RemoveBasePathVersion(p.DNSBasePath) - dnsClientBasePath = strings.ReplaceAll(dnsClientBasePath, "/dns/", "") - tflog.Info(p.Context, fmt.Sprintf("Instantiating Google Cloud DNS client for path %s", dnsClientBasePath)) - clientDns, err := dns.NewService(p.Context, option.WithHTTPClient(p.Client)) - if err != nil { - diags.AddWarning("error creating client dns", err.Error()) - return nil - } - clientDns.UserAgent = userAgent - clientDns.BasePath = dnsClientBasePath - - return clientDns -} - -{{ if ne $.TargetVersionName `ga` -}} -func (p *FrameworkProviderConfig) NewFirebaseClient(userAgent string, diags *diag.Diagnostics) *firebase.Service { - firebaseClientBasePath := transport_tpg.RemoveBasePathVersion(p.FirebaseBasePath) - firebaseClientBasePath = strings.ReplaceAll(firebaseClientBasePath, "/firebase/", "") - tflog.Info(p.Context, fmt.Sprintf("Instantiating Google Cloud firebase client for path %s", firebaseClientBasePath)) - clientFirebase, err := firebase.NewService(p.Context, option.WithHTTPClient(p.Client)) - if err != nil { - diags.AddWarning("error creating client firebase", err.Error()) - return nil - } - clientFirebase.UserAgent = userAgent - clientFirebase.BasePath = firebaseClientBasePath - - return clientFirebase -} -{{- end }} diff --git a/mmv1/third_party/terraform/fwtransport/framework_transport.go b/mmv1/third_party/terraform/fwtransport/framework_transport.go deleted file mode 100644 index 9764518c506b..000000000000 --- a/mmv1/third_party/terraform/fwtransport/framework_transport.go +++ /dev/null @@ -1,103 +0,0 @@ -package fwtransport - -import ( - "bytes" - "encoding/json" - "net/http" - "time" - - "github.com/hashicorp/terraform-plugin-framework/diag" - transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" - - "google.golang.org/api/googleapi" -) - -func SendFrameworkRequest(p *FrameworkProviderConfig, method, project, rawurl, userAgent string, body map[string]interface{}, errorRetryPredicates ...transport_tpg.RetryErrorPredicateFunc) (map[string]interface{}, diag.Diagnostics) { - return SendFrameworkRequestWithTimeout(p, method, project, rawurl, userAgent, body, transport_tpg.DefaultRequestTimeout, errorRetryPredicates...) -} - -func SendFrameworkRequestWithTimeout(p *FrameworkProviderConfig, method, project, rawurl, userAgent string, body map[string]interface{}, timeout time.Duration, errorRetryPredicates ...transport_tpg.RetryErrorPredicateFunc) (map[string]interface{}, diag.Diagnostics) { - var diags diag.Diagnostics - - reqHeaders := make(http.Header) - reqHeaders.Set("User-Agent", userAgent) - reqHeaders.Set("Content-Type", "application/json") - - if p.UserProjectOverride.ValueBool() && project != "" { - // When project is "NO_BILLING_PROJECT_OVERRIDE" in the function GetCurrentUserEmail, - // set the header X-Goog-User-Project to be empty string. - if project == "NO_BILLING_PROJECT_OVERRIDE" { - reqHeaders.Set("X-Goog-User-Project", "") - } else { - // Pass the project into this fn instead of parsing it from the URL because - // both project names and URLs can have colons in them. - reqHeaders.Set("X-Goog-User-Project", project) - } - } - - if timeout == 0 { - timeout = time.Hour - } - - var res *http.Response - err := transport_tpg.Retry(transport_tpg.RetryOptions{ - RetryFunc: func() error { - var buf bytes.Buffer - if body != nil { - err := json.NewEncoder(&buf).Encode(body) - if err != nil { - return err - } - } - - u, err := transport_tpg.AddQueryParams(rawurl, map[string]string{"alt": "json"}) - if err != nil { - return err - } - req, err := http.NewRequest(method, u, &buf) - if err != nil { - return err - } - - req.Header = reqHeaders - res, err = p.Client.Do(req) - if err != nil { - return err - } - - if err := googleapi.CheckResponse(res); err != nil { - googleapi.CloseBody(res) - return err - } - - return nil - }, - Timeout: timeout, - ErrorRetryPredicates: errorRetryPredicates, - }) - if err != nil { - diags.AddError("error sending request", err.Error()) - return nil, diags - } - - if res == nil { - diags.AddError("Unable to parse server response.", "This is most likely a terraform problem, please file a bug at https://github.com/hashicorp/terraform-provider-google/issues.") - return nil, diags - } - - // The defer call must be made outside of the retryFunc otherwise it's closed too soon. - defer googleapi.CloseBody(res) - - // 204 responses will have no body, so we're going to error with "EOF" if we - // try to parse it. Instead, we can just return nil. - if res.StatusCode == 204 { - return nil, diags - } - result := make(map[string]interface{}) - if err := json.NewDecoder(res.Body).Decode(&result); err != nil { - diags.AddError("error decoding response body", err.Error()) - return nil, diags - } - - return result, diags -} diff --git a/mmv1/third_party/terraform/fwtransport/framework_utils.go b/mmv1/third_party/terraform/fwtransport/framework_utils.go index a59dd230bdfe..b297b475cb25 100644 --- a/mmv1/third_party/terraform/fwtransport/framework_utils.go +++ b/mmv1/third_party/terraform/fwtransport/framework_utils.go @@ -30,28 +30,6 @@ func CompileUserAgentString(ctx context.Context, name, tfVersion, provVersion st return ua } -func GetCurrentUserEmailFramework(p *FrameworkProviderConfig, userAgent string, diags *diag.Diagnostics) string { - // When environment variables UserProjectOverride and BillingProject are set for the provider, - // the header X-Goog-User-Project is set for the API requests. - // But it causes an error when calling GetCurrUserEmail. Set the project to be "NO_BILLING_PROJECT_OVERRIDE". - // And then it triggers the header X-Goog-User-Project to be set to empty string. - - // See https://github.com/golang/oauth2/issues/306 for a recommendation to do this from a Go maintainer - // URL retrieved from https://accounts.google.com/.well-known/openid-configuration - res, d := SendFrameworkRequest(p, "GET", "NO_BILLING_PROJECT_OVERRIDE", "https://openidconnect.googleapis.com/v1/userinfo", userAgent, nil) - diags.Append(d...) - - if diags.HasError() { - tflog.Info(p.Context, "error retrieving userinfo for your provider credentials. have you enabled the 'https://www.googleapis.com/auth/userinfo.email' scope?") - return "" - } - if res["email"] == nil { - diags.AddError("error retrieving email from userinfo.", "email was nil in the response.") - return "" - } - return res["email"].(string) -} - func GenerateFrameworkUserAgentString(metaData *fwmodels.ProviderMetaModel, currUserAgent string) string { if metaData != nil && !metaData.ModuleName.IsNull() && metaData.ModuleName.ValueString() != "" { return strings.Join([]string{currUserAgent, metaData.ModuleName.ValueString()}, " ") diff --git a/mmv1/third_party/terraform/fwutils/utils.go b/mmv1/third_party/terraform/fwutils/utils.go new file mode 100644 index 000000000000..eee57edde3c8 --- /dev/null +++ b/mmv1/third_party/terraform/fwutils/utils.go @@ -0,0 +1,12 @@ +package fwutils + +import "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + +func StringSet(d basetypes.SetValue) []string { + + StringSlice := make([]string, 0) + for _, v := range d.Elements() { + StringSlice = append(StringSlice, v.(basetypes.StringValue).ValueString()) + } + return StringSlice +} diff --git a/mmv1/third_party/terraform/fwprovider/framework_validators.go b/mmv1/third_party/terraform/fwvalidators/framework_validators.go similarity index 55% rename from mmv1/third_party/terraform/fwprovider/framework_validators.go rename to mmv1/third_party/terraform/fwvalidators/framework_validators.go index 3af98fd9db92..f0c273df7e96 100644 --- a/mmv1/third_party/terraform/fwprovider/framework_validators.go +++ b/mmv1/third_party/terraform/fwvalidators/framework_validators.go @@ -1,9 +1,10 @@ -package fwprovider +package fwvalidators import ( "context" "fmt" "os" + "regexp" "time" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -115,3 +116,93 @@ func (v nonEmptyStringValidator) ValidateString(ctx context.Context, request val func NonEmptyStringValidator() validator.String { return nonEmptyStringValidator{} } + +// Define the possible service account name patterns +var ServiceAccountEmailPatterns = []string{ + `^.+@.+\.iam\.gserviceaccount\.com$`, // Standard IAM service account + `^.+@developer\.gserviceaccount\.com$`, // Legacy developer service account + `^.+@appspot\.gserviceaccount\.com$`, // App Engine service account + `^.+@cloudservices\.gserviceaccount\.com$`, // Google Cloud services service account + `^.+@cloudbuild\.gserviceaccount\.com$`, // Cloud Build service account + `^service-[0-9]+@.+-compute\.iam\.gserviceaccount\.com$`, // Compute Engine service account +} + +// Create a custom validator for service account names +type ServiceAccountEmailValidator struct{} + +func (v ServiceAccountEmailValidator) Description(ctx context.Context) string { + return "value must be a valid service account email address" +} + +func (v ServiceAccountEmailValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +func (v ServiceAccountEmailValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() { + return + } + + value := req.ConfigValue.ValueString() + + // Check for empty string + if value == "" { + resp.Diagnostics.AddError("Invalid Service Account Name", "Service account name must not be empty") + return + } + + valid := false + for _, pattern := range ServiceAccountEmailPatterns { + if matched, _ := regexp.MatchString(pattern, value); matched { + valid = true + break + } + } + + if !valid { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid Service Account Name", + "Service account name must match one of the expected patterns for Google service accounts", + ) + } +} + +// Create a custom validator for duration +type BoundedDuration struct { + MinDuration time.Duration + MaxDuration time.Duration +} + +func (v BoundedDuration) Description(ctx context.Context) string { + return fmt.Sprintf("value must be a valid duration string between %v and %v", v.MinDuration, v.MaxDuration) +} + +func (v BoundedDuration) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +func (v BoundedDuration) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { + if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() { + return + } + + value := req.ConfigValue.ValueString() + duration, err := time.ParseDuration(value) + if err != nil { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid Duration Format", + "Duration must be a valid duration string (e.g., '3600s', '1h')", + ) + return + } + + if duration < v.MinDuration || duration > v.MaxDuration { + resp.Diagnostics.AddAttributeError( + req.Path, + "Invalid Duration", + fmt.Sprintf("Duration must be between %v and %v", v.MinDuration, v.MaxDuration), + ) + } +} diff --git a/mmv1/third_party/terraform/fwvalidators/framework_validators_test.go b/mmv1/third_party/terraform/fwvalidators/framework_validators_test.go new file mode 100644 index 000000000000..07e2378e8bf3 --- /dev/null +++ b/mmv1/third_party/terraform/fwvalidators/framework_validators_test.go @@ -0,0 +1,309 @@ +package fwvalidators_test + +import ( + "context" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/fwvalidators" + + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestFrameworkProvider_CredentialsValidator(t *testing.T) { + cases := map[string]struct { + ConfigValue types.String + ExpectedWarningCount int + ExpectedErrorCount int + }{ + "configuring credentials as a path to a credentials JSON file is valid": { + ConfigValue: types.StringValue(transport_tpg.TestFakeCredentialsPath), // Path to a test fixture + }, + "configuring credentials as a path to a non-existent file is NOT valid": { + ConfigValue: types.StringValue("./this/path/doesnt/exist.json"), // Doesn't exist + ExpectedErrorCount: 1, + }, + "configuring credentials as a credentials JSON string is valid": { + ConfigValue: types.StringValue(acctest.GenerateFakeCredentialsJson("CredentialsValidator")), + }, + "configuring credentials as an empty string is not valid": { + ConfigValue: types.StringValue(""), + ExpectedErrorCount: 1, + }, + "leaving credentials unconfigured is valid": { + ConfigValue: types.StringNull(), + }, + } + + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + // Arrange + req := validator.StringRequest{ + ConfigValue: tc.ConfigValue, + } + + resp := validator.StringResponse{ + Diagnostics: diag.Diagnostics{}, + } + + cv := fwvalidators.CredentialsValidator() + + // Act + cv.ValidateString(context.Background(), req, &resp) + + // Assert + if resp.Diagnostics.WarningsCount() > tc.ExpectedWarningCount { + t.Errorf("Expected %d warnings, got %d", tc.ExpectedWarningCount, resp.Diagnostics.WarningsCount()) + } + if resp.Diagnostics.ErrorsCount() > tc.ExpectedErrorCount { + t.Errorf("Expected %d errors, got %d", tc.ExpectedErrorCount, resp.Diagnostics.ErrorsCount()) + } + }) + } +} + +func TestServiceAccountEmailValidator(t *testing.T) { + t.Parallel() + + type testCase struct { + value types.String + expectError bool + errorContains string + } + + tests := map[string]testCase{ + "correct service account name": { + value: types.StringValue("test@test.iam.gserviceaccount.com"), + expectError: false, + }, + "developer service account": { + value: types.StringValue("test@developer.gserviceaccount.com"), + expectError: false, + }, + "app engine service account": { + value: types.StringValue("test@appspot.gserviceaccount.com"), + expectError: false, + }, + "cloud services service account": { + value: types.StringValue("test@cloudservices.gserviceaccount.com"), + expectError: false, + }, + "cloud build service account": { + value: types.StringValue("test@cloudbuild.gserviceaccount.com"), + expectError: false, + }, + "compute engine service account": { + value: types.StringValue("service-123456@compute-system.iam.gserviceaccount.com"), + expectError: false, + }, + "incorrect service account name": { + value: types.StringValue("test"), + expectError: true, + errorContains: "Service account name must match one of the expected patterns for Google service accounts", + }, + "empty string": { + value: types.StringValue(""), + expectError: true, + errorContains: "Service account name must not be empty", + }, + "null value": { + value: types.StringNull(), + expectError: false, + }, + "unknown value": { + value: types.StringUnknown(), + expectError: false, + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + t.Parallel() + + request := validator.StringRequest{ + Path: path.Root("test"), + PathExpression: path.MatchRoot("test"), + ConfigValue: test.value, + } + response := validator.StringResponse{} + validator := fwvalidators.ServiceAccountEmailValidator{} + + validator.ValidateString(context.Background(), request, &response) + + if test.expectError && !response.Diagnostics.HasError() { + t.Errorf("expected error, got none") + } + + if !test.expectError && response.Diagnostics.HasError() { + t.Errorf("got unexpected error: %s", response.Diagnostics.Errors()) + } + + if test.errorContains != "" { + foundError := false + for _, err := range response.Diagnostics.Errors() { + if err.Detail() == test.errorContains { + foundError = true + break + } + } + if !foundError { + t.Errorf("expected error with summary %q, got none", test.errorContains) + } + } + }) + } +} + +func TestBoundedDuration(t *testing.T) { + t.Parallel() + + type testCase struct { + value types.String + minDuration time.Duration + maxDuration time.Duration + expectError bool + errorContains string + } + + tests := map[string]testCase{ + "valid duration between min and max": { + value: types.StringValue("1800s"), + minDuration: time.Hour / 2, + maxDuration: time.Hour, + expectError: false, + }, + "valid duration at min": { + value: types.StringValue("1800s"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: false, + }, + "valid duration at max": { + value: types.StringValue("3600s"), + minDuration: time.Hour / 2, + maxDuration: time.Hour, + expectError: false, + }, + "valid duration with different unit": { + value: types.StringValue("1h"), + minDuration: 30 * time.Minute, + maxDuration: 2 * time.Hour, + expectError: false, + }, + "duration below min": { + value: types.StringValue("900s"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration", + }, + "duration exceeds max - seconds": { + value: types.StringValue("7200s"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration", + }, + "duration exceeds max - minutes": { + value: types.StringValue("120m"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration", + }, + "duration exceeds max - hours": { + value: types.StringValue("2h"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration", + }, + "invalid duration format": { + value: types.StringValue("invalid"), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration Format", + }, + "setting min to 0": { + value: types.StringValue("10s"), + minDuration: 0, + maxDuration: time.Hour, + expectError: false, + }, + "setting max to be less than min": { + value: types.StringValue("10s"), + minDuration: 30 * time.Minute, + maxDuration: 10 * time.Second, + expectError: true, + errorContains: "Invalid Duration", + }, + "empty string": { + value: types.StringValue(""), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: true, + errorContains: "Invalid Duration Format", + }, + "null value": { + value: types.StringNull(), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: false, + }, + "unknown value": { + value: types.StringUnknown(), + minDuration: 30 * time.Minute, + maxDuration: time.Hour, + expectError: false, + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + t.Parallel() + + request := validator.StringRequest{ + Path: path.Root("test"), + PathExpression: path.MatchRoot("test"), + ConfigValue: test.value, + } + response := validator.StringResponse{} + validator := fwvalidators.BoundedDuration{ + MinDuration: test.minDuration, + MaxDuration: test.maxDuration, + } + + validator.ValidateString(context.Background(), request, &response) + + if test.expectError && !response.Diagnostics.HasError() { + t.Errorf("expected error, got none") + } + + if !test.expectError && response.Diagnostics.HasError() { + t.Errorf("got unexpected error: %s", response.Diagnostics.Errors()) + } + + if test.errorContains != "" { + foundError := false + for _, err := range response.Diagnostics.Errors() { + if err.Summary() == test.errorContains { + foundError = true + break + } + } + if !foundError { + t.Errorf("expected error with summary %q, got none", test.errorContains) + } + } + }) + } +} diff --git a/mmv1/third_party/terraform/go.mod b/mmv1/third_party/terraform/go.mod index 11c5e642481a..b719305f31e8 100644 --- a/mmv1/third_party/terraform/go.mod +++ b/mmv1/third_party/terraform/go.mod @@ -4,7 +4,7 @@ go 1.23 require ( cloud.google.com/go/bigtable v1.33.0 - github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0 + github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0 github.com/apparentlymart/go-cidr v1.1.0 github.com/davecgh/go-spew v1.1.1 github.com/dnaeon/go-vcr v1.0.1 @@ -17,11 +17,11 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/terraform-json v0.22.1 - github.com/hashicorp/terraform-plugin-framework v1.7.0 + github.com/hashicorp/terraform-plugin-framework v1.13.0 github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 - github.com/hashicorp/terraform-plugin-go v0.23.0 + github.com/hashicorp/terraform-plugin-go v0.25.0 github.com/hashicorp/terraform-plugin-log v0.9.0 - github.com/hashicorp/terraform-plugin-mux v0.15.0 + github.com/hashicorp/terraform-plugin-mux v0.17.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 github.com/hashicorp/terraform-plugin-testing v1.5.1 github.com/mitchellh/go-homedir v1.1.0 @@ -73,7 +73,7 @@ require ( github.com/googleapis/gax-go/v2 v2.14.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-plugin v1.6.0 // indirect + github.com/hashicorp/go-plugin v1.6.2 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/hc-install v0.6.4 // indirect github.com/hashicorp/hcl/v2 v2.20.1 // indirect @@ -118,4 +118,4 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect -) \ No newline at end of file +) diff --git a/mmv1/third_party/terraform/go.sum b/mmv1/third_party/terraform/go.sum index fcc915d85ff6..202ee1ad291f 100644 --- a/mmv1/third_party/terraform/go.sum +++ b/mmv1/third_party/terraform/go.sum @@ -22,8 +22,8 @@ cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0 h1:7tFkHNjfjm7dYnjqyuzMon+31lPaMTjca3OuamWd0Oo= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0 h1:VH/j8GmTsvPds/NkGfo4OYr9C7R8ysikaqq4rcDUT0s= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg= @@ -154,8 +154,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1 github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= -github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= +github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= +github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -171,16 +171,16 @@ github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVW github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec= github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A= -github.com/hashicorp/terraform-plugin-framework v1.7.0 h1:wOULbVmfONnJo9iq7/q+iBOBJul5vRovaYJIu2cY/Pw= -github.com/hashicorp/terraform-plugin-framework v1.7.0/go.mod h1:jY9Id+3KbZ17OMpulgnWLSfwxNVYSoYBQFTgsx044CI= +github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw= +github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU= github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 h1:LYz4bXh3t7bTEydXOmPDPupRRnA480B/9+jV8yZvxBA= github.com/hashicorp/terraform-plugin-framework-validators v0.9.0/go.mod h1:+BVERsnfdlhYR2YkXMBtPnmn9UsL19U3qUtSZ+Y/5MY= -github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co= -github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ= +github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks= +github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= -github.com/hashicorp/terraform-plugin-mux v0.15.0 h1:+/+lDx0WUsIOpkAmdwBIoFU8UP9o2eZASoOnLsWbKME= -github.com/hashicorp/terraform-plugin-mux v0.15.0/go.mod h1:9ezplb1Dyq394zQ+ldB0nvy/qbNAz3mMoHHseMTMaKo= +github.com/hashicorp/terraform-plugin-mux v0.17.0 h1:/J3vv3Ps2ISkbLPiZOLspFcIZ0v5ycUXCEQScudGCCw= +github.com/hashicorp/terraform-plugin-mux v0.17.0/go.mod h1:yWuM9U1Jg8DryNfvCp+lH70WcYv6D8aooQxxxIzFDsE= github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 h1:qHprzXy/As0rxedphECBEQAh3R4yp6pKksKHcqZx5G8= github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0/go.mod h1:H+8tjs9TjV2w57QFVSMBQacf8k/E1XwLXGCARgViC6A= github.com/hashicorp/terraform-plugin-testing v1.5.1 h1:T4aQh9JAhmWo4+t1A7x+rnxAJHCDIYW9kXyo4sVO92c= diff --git a/mmv1/third_party/terraform/main.go.tmpl b/mmv1/third_party/terraform/main.go.tmpl index 8bb1fb9fd4de..928a117a33db 100644 --- a/mmv1/third_party/terraform/main.go.tmpl +++ b/mmv1/third_party/terraform/main.go.tmpl @@ -20,10 +20,12 @@ func main() { flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") flag.Parse() - // concat with sdkv2 provider + // primary is the SDKv2 implementation of the provider + primary := provider.Provider() + providers := []func() tfprotov5.ProviderServer{ - providerserver.NewProtocol5(fwprovider.New()), // framework provider - provider.Provider().GRPCProvider, // sdk provider + primary.GRPCProvider, // sdk provider + providerserver.NewProtocol5(fwprovider.New(primary)), // framework provider } // use the muxer diff --git a/mmv1/third_party/terraform/provider/provider.go.tmpl b/mmv1/third_party/terraform/provider/provider.go.tmpl index bece351a6b7f..066592474b49 100644 --- a/mmv1/third_party/terraform/provider/provider.go.tmpl +++ b/mmv1/third_party/terraform/provider/provider.go.tmpl @@ -29,6 +29,9 @@ func Provider() *schema.Provider { } provider := &schema.Provider{ + // See: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux + // "The schema and configuration handling must exactly match between all underlying providers of the mux server" + // This schema matches the schema implemented with the plugin-framework in google/fwprovider/framework_provider.go Schema: map[string]*schema.Schema{ "credentials": { Type: schema.TypeString, diff --git a/mmv1/third_party/terraform/provider/provider_internal_test.go b/mmv1/third_party/terraform/provider/provider_internal_test.go index 4b10ff1c55a6..6b4c103ca469 100644 --- a/mmv1/third_party/terraform/provider/provider_internal_test.go +++ b/mmv1/third_party/terraform/provider/provider_internal_test.go @@ -24,7 +24,7 @@ func TestProvider_ValidateCredentials(t *testing.T) { return transport_tpg.TestFakeCredentialsPath // Path to a test fixture }, }, - "configuring credentials as a path to a non-existant file is NOT valid": { + "configuring credentials as a path to a non-existent file is NOT valid": { ConfigValue: func(t *testing.T) interface{} { return "./this/path/doesnt/exist.json" // Doesn't exist }, diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl index 9ac625153e69..6f1643252c7e 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl @@ -7,9 +7,6 @@ import ( "github.com/hashicorp/terraform-provider-google/google/services/{{ $service }}" {{- end }} - {{ if eq $.TargetVersionName `ga` }} - "github.com/hashicorp/terraform-provider-google/google/services/composer" - {{- end }} "github.com/hashicorp/terraform-provider-google/google/services/container" "github.com/hashicorp/terraform-provider-google/google/services/containeraws" "github.com/hashicorp/terraform-provider-google/google/services/containerazure" @@ -38,8 +35,10 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_backup_dr_management_server": backupdr.DataSourceGoogleCloudBackupDRService(), "google_backup_dr_backup_plan_association": backupdr.DataSourceGoogleCloudBackupDRBackupPlanAssociation(), "google_backup_dr_backup_plan": backupdr.DataSourceGoogleCloudBackupDRBackupPlan(), - "google_backup_dr_data_source": backupdr.DataSourceGoogleCloudBackupDRDataSource(), {{- end }} + "google_backup_dr_backup": backupdr.DataSourceGoogleCloudBackupDRBackup(), + "google_backup_dr_data_source": backupdr.DataSourceGoogleCloudBackupDRDataSource(), + "google_backup_dr_backup_vault": backupdr.DataSourceGoogleCloudBackupDRBackupVault(), "google_beyondcorp_app_connection": beyondcorp.DataSourceGoogleBeyondcorpAppConnection(), "google_beyondcorp_app_connector": beyondcorp.DataSourceGoogleBeyondcorpAppConnector(), "google_beyondcorp_app_gateway": beyondcorp.DataSourceGoogleBeyondcorpAppGateway(), @@ -67,10 +66,8 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_cloud_run_v2_job": cloudrunv2.DataSourceGoogleCloudRunV2Job(), "google_cloud_run_v2_service": cloudrunv2.DataSourceGoogleCloudRunV2Service(), "google_composer_environment": composer.DataSourceGoogleComposerEnvironment(), - {{- if ne $.TargetVersionName "ga" }} "google_composer_user_workloads_config_map": composer.DataSourceGoogleComposerUserWorkloadsConfigMap(), "google_composer_user_workloads_secret": composer.DataSourceGoogleComposerUserWorkloadsSecret(), - {{- end }} "google_composer_image_versions": composer.DataSourceGoogleComposerImageVersions(), "google_compute_address": compute.DataSourceGoogleComputeAddress(), "google_compute_addresses": compute.DataSourceGoogleComputeAddresses(), @@ -323,9 +320,7 @@ var handwrittenResources = map[string]*schema.Resource{ "google_billing_subaccount": resourcemanager.ResourceBillingSubaccount(), "google_cloudfunctions_function": cloudfunctions.ResourceCloudFunctionsFunction(), "google_composer_environment": composer.ResourceComposerEnvironment(), - {{- if ne $.TargetVersionName "ga" }} "google_composer_user_workloads_secret": composer.ResourceComposerUserWorkloadsSecret(), - {{- end }} "google_compute_attached_disk": compute.ResourceComputeAttachedDisk(), "google_compute_instance": compute.ResourceComputeInstance(), "google_compute_disk_async_replication": compute.ResourceComputeDiskAsyncReplication(), diff --git a/mmv1/third_party/terraform/provider/provider_request_timeout_test.go b/mmv1/third_party/terraform/provider/provider_request_timeout_test.go index cd57877a8bf4..b48802d07ce1 100644 --- a/mmv1/third_party/terraform/provider/provider_request_timeout_test.go +++ b/mmv1/third_party/terraform/provider/provider_request_timeout_test.go @@ -62,6 +62,8 @@ func testAccSdkProvider_request_timeout_setInConfig(t *testing.T) { providerTimeout1 := "3m0s" providerTimeout2 := "3m" + + // All inputs are normalised to this expectedValue := "3m0s" context1 := map[string]interface{}{ diff --git a/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go b/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go index 8ea474505ac4..ea2703508e3b 100644 --- a/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go +++ b/mmv1/third_party/terraform/provider/universe/universe_domain_compute_test.go @@ -26,7 +26,7 @@ func TestAccUniverseDomainDisk(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckComputeDiskDestroyProducer(t), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccUniverseDomain_basic_disk(universeDomain), }, }, @@ -41,7 +41,7 @@ func TestAccDefaultUniverseDomainDisk(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckComputeDiskDestroyProducer(t), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccUniverseDomain_basic_disk(universeDomain), }, }, @@ -55,7 +55,7 @@ func TestAccDefaultUniverseDomain_doesNotMatchExplicit(t *testing.T) { PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccUniverseDomain_basic_disk(universeDomainFake), ExpectError: regexp.MustCompile("Universe domain mismatch"), }, diff --git a/mmv1/third_party/terraform/provider/universe/universe_domain_pubsub_test.go b/mmv1/third_party/terraform/provider/universe/universe_domain_pubsub_test.go index 92a55e5d2b72..09fbfd05baa7 100644 --- a/mmv1/third_party/terraform/provider/universe/universe_domain_pubsub_test.go +++ b/mmv1/third_party/terraform/provider/universe/universe_domain_pubsub_test.go @@ -27,7 +27,7 @@ func TestAccUniverseDomainPubSub(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckPubsubSubscriptionDestroyProducer(t), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccUniverseDomain_basic_pubsub(universeDomain, topic, subscription), }, }, diff --git a/mmv1/third_party/terraform/provider/universe/universe_domain_storage_test.go b/mmv1/third_party/terraform/provider/universe/universe_domain_storage_test.go index 889edc716a57..259fe944968c 100644 --- a/mmv1/third_party/terraform/provider/universe/universe_domain_storage_test.go +++ b/mmv1/third_party/terraform/provider/universe/universe_domain_storage_test.go @@ -24,7 +24,7 @@ func TestAccUniverseDomainStorage(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccStorageBucketDestroyProducer(t), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccUniverseDomain_bucket(universeDomain, bucketName), }, }, diff --git a/mmv1/third_party/terraform/services/accesscontextmanager/resource_access_context_manager_service_perimeter_test.go.tmpl b/mmv1/third_party/terraform/services/accesscontextmanager/resource_access_context_manager_service_perimeter_test.go.tmpl index 38271404e07d..7007104794ec 100644 --- a/mmv1/third_party/terraform/services/accesscontextmanager/resource_access_context_manager_service_perimeter_test.go.tmpl +++ b/mmv1/third_party/terraform/services/accesscontextmanager/resource_access_context_manager_service_perimeter_test.go.tmpl @@ -26,6 +26,7 @@ func testAccAccessContextManagerServicePerimeter_basicTest(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccAccessContextManagerServicePerimeter_basic(org, "my policy", "level", "perimeter"), + Check: resource.TestCheckResourceAttrSet("google_access_context_manager_service_perimeter.test-access", "etag"), }, { ResourceName: "google_access_context_manager_service_perimeter.test-access", @@ -412,7 +413,7 @@ resource "google_access_context_manager_service_perimeter" "test-access" { } -type IdentityTypeDiffSupressFuncDiffSuppressTestCase struct { +type IdentityTypeDiffSuppressFuncDiffSuppressTestCase struct { Name string AreEqual bool Before string @@ -420,7 +421,7 @@ type IdentityTypeDiffSupressFuncDiffSuppressTestCase struct { } -var identityTypeDiffSuppressTestCases = []IdentityTypeDiffSupressFuncDiffSuppressTestCase{ +var identityTypeDiffSuppressTestCases = []IdentityTypeDiffSuppressFuncDiffSuppressTestCase{ { AreEqual: false, Before: "A", @@ -460,8 +461,8 @@ func TestUnitAccessContextManagerServicePerimeter_identityTypeDiff(t *testing.T) } -func (tc *IdentityTypeDiffSupressFuncDiffSuppressTestCase) Test(t *testing.T) { - actual := accesscontextmanager.AccessContextManagerServicePerimeterIdentityTypeDiffSupressFunc("", tc.Before, tc.After, nil) +func (tc *IdentityTypeDiffSuppressFuncDiffSuppressTestCase) Test(t *testing.T) { + actual := accesscontextmanager.AccessContextManagerServicePerimeterIdentityTypeDiffSuppressFunc("", tc.Before, tc.After, nil) if actual != tc.AreEqual { t.Errorf( "Unexpected difference found. Before: \"%s\", after: \"%s\", actual: %t, expected: %t", diff --git a/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_cluster_test.go b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_cluster_test.go index 6bb2ff2ab9b2..470a1ef6e7ed 100644 --- a/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_cluster_test.go +++ b/mmv1/third_party/terraform/services/alloydb/resource_alloydb_secondary_cluster_test.go @@ -1229,7 +1229,7 @@ data "google_compute_global_address" "private_ip_alloc" { `, context) } -// This test passes if automated backup policy and inital user can be added and deleted from the promoted secondary cluster +// This test passes if automated backup policy and initial user can be added and deleted from the promoted secondary cluster func TestAccAlloydbCluster_secondaryClusterPromoteAndAddAndDeleteAutomatedBackupPolicyAndInitialUser(t *testing.T) { t.Parallel() diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_api_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_api_meta.yaml new file mode 100644 index 000000000000..3c2715af8300 --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_api_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_api' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ApiProxy' diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_developer_update_test.go b/mmv1/third_party/terraform/services/apigee/resource_apigee_developer_update_test.go index 0f5c19918bdf..e979119c60f9 100644 --- a/mmv1/third_party/terraform/services/apigee/resource_apigee_developer_update_test.go +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_developer_update_test.go @@ -21,7 +21,10 @@ func TestAccApigeeDeveloper_apigeeDeveloperUpdateTest(t *testing.T) { acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckApigeeDeveloperDestroyProducer(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + CheckDestroy: testAccCheckApigeeDeveloperDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccApigeeDeveloper_apigeeDeveloperBasicTestExample(context), @@ -55,19 +58,27 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "compute" { project = google_project.project.project_id service = "compute.googleapis.com" + depends_on = [google_project_service.apigee] } resource "google_project_service" "servicenetworking" { project = google_project.project.project_id service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.compute] } resource "google_compute_network" "apigee_network" { diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.tmpl b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.tmpl index 3660864ab62f..b86ec238dd96 100644 --- a/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.tmpl +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_type_test.go.tmpl @@ -22,6 +22,9 @@ func TestAccApigeeEnvironment_apigeeEnvironmentPatchUpdateTestExampleUpdate(t *t acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, CheckDestroy: testAccCheckApigeeEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ { diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_update_test.go b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_update_test.go index 106da737aed5..6ceb7d1510ba 100644 --- a/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_update_test.go +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_environment_update_test.go @@ -21,7 +21,10 @@ func TestAccApigeeEnvironment_apigeeEnvironmentUpdateTest(t *testing.T) { acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckApigeeEnvironmentDestroyProducer(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + CheckDestroy: testAccCheckApigeeEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccApigeeEnvironment_apigeeEnvironmentBasicTestExample(context), @@ -55,9 +58,15 @@ resource "google_project" "project" { deletion_policy = "DELETE" } +resource "time_sleep" "wait_60_seconds" { + create_duration = "60s" + depends_on = [google_project.project] +} + resource "google_project_service" "apigee" { project = google_project.project.project_id service = "apigee.googleapis.com" + depends_on = [time_sleep.wait_60_seconds] } resource "google_project_service" "servicenetworking" { diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_flowhook_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_flowhook_meta.yaml new file mode 100644 index 000000000000..8bab9a5ed71b --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_flowhook_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_flowhook' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'FlowHook' diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_key_cert_file_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_key_cert_file_meta.yaml new file mode 100644 index 000000000000..2a1e2005d34a --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_key_cert_file_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_keystores_aliases_key_cert_file' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Alias' diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_env_keystore_alias_pkcs12.go b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12.go similarity index 100% rename from mmv1/third_party/terraform/services/apigee/resource_apigee_env_keystore_alias_pkcs12.go rename to mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12.go diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12_meta.yaml new file mode 100644 index 000000000000..e169d7bb94d8 --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_keystores_aliases_pkcs12' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Alias' diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_env_keystore_alias_pkcs12_test.go b/mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12_test.go similarity index 100% rename from mmv1/third_party/terraform/services/apigee/resource_apigee_env_keystore_alias_pkcs12_test.go rename to mmv1/third_party/terraform/services/apigee/resource_apigee_keystores_aliases_pkcs12_test.go diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_deployment_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_deployment_meta.yaml new file mode 100644 index 000000000000..f6cff2c6bccd --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_deployment_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_sharedflow_deployment' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'SharedFlow' diff --git a/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_meta.yaml b/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_meta.yaml new file mode 100644 index 000000000000..56f345484391 --- /dev/null +++ b/mmv1/third_party/terraform/services/apigee/resource_apigee_sharedflow_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_apigee_sharedflow' +generation_type: 'handwritten' +api_service_name: 'apigee.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'SharedFlow' diff --git a/mmv1/third_party/terraform/services/appengine/resource_app_engine_application_meta.yaml.tmpl b/mmv1/third_party/terraform/services/appengine/resource_app_engine_application_meta.yaml.tmpl new file mode 100644 index 000000000000..b9ca88e7ccaa --- /dev/null +++ b/mmv1/third_party/terraform/services/appengine/resource_app_engine_application_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_app_engine_application' +generation_type: 'handwritten' +api_service_name: 'appengine.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'v1beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Application' diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup.go.tmpl b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup.go.tmpl new file mode 100644 index 000000000000..944e547352d3 --- /dev/null +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup.go.tmpl @@ -0,0 +1,172 @@ +package backupdr + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func DataSourceGoogleCloudBackupDRBackup() *schema.Resource { + dsSchema := map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `Name of resource`, + }, + "backups": { + Type: schema.TypeList, + Computed: true, + Description: `List of all backups under data source.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + Description: `Name of the resource.`, + }, + "location": { + Type: schema.TypeString, + Computed: true, + Description: `Location of the resource.`, + }, + "backup_id": { + Type: schema.TypeString, + Computed: true, + Description: `Id of the requesting object, Backup.`, + }, + "backup_vault_id": { + Type: schema.TypeString, + Computed: true, + Description: `Name of the Backup Vault associated with Backup.`, + }, + "data_source_id": { + Type: schema.TypeString, + Computed: true, + Description: `Name of the Data Source associated with Backup.`, + }, + }, + }, + }, + "location": { + Type: schema.TypeString, + Required: true, + }, + "project": { + Type: schema.TypeString, + Required: true, + }, + "data_source_id": { + Type: schema.TypeString, + Required: true, + }, + "backup_vault_id": { + Type: schema.TypeString, + Required: true, + }, + } + + return &schema.Resource{ + Read: dataSourceGoogleCloudBackupDrBackupRead, + Schema: dsSchema, + } +} + +func dataSourceGoogleCloudBackupDrBackupRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + location, err := tpgresource.GetLocation(d, config) + if err != nil { + return err + } + if len(location) == 0 { + return fmt.Errorf("Cannot determine location: set location in this data source or at provider-level") + } + + billingProject := project + url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}BackupDRBasePath{{"}}"}}projects/{{"{{"}}project{{"}}"}}/locations/{{"{{"}}location{{"}}"}}/backupVaults/{{"{{"}}backup_vault_id{{"}}"}}/dataSources/{{"{{"}}data_source_id{{"}}"}}/backups") + + fmt.Sprintf("url: %s", url) + + if err != nil { + return err + } + + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + + if err != nil { + return fmt.Errorf("Error reading BackupVault: %s", err) + } + + if err := d.Set("backups", flattenDataSourceBackupDRBackups(res["backups"], d, config)); err != nil { + return fmt.Errorf("Error reading Backup: %s", err) + } + + id, err := tpgresource.ReplaceVars(d, config, "projects/{{"{{"}}project{{"}}"}}/locations/{{"{{"}}location{{"}}"}}/backupVaults/{{"{{"}}backup_vault_id{{"}}"}}/dataSources/{{"{{"}}data_source_id{{"}}"}}/backups") + d.SetId(id) + d.Set("name", id) + + return nil +} + +func flattenDataSourceBackupDRBackups(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 { + continue + } + transformed = append(transformed, map[string]interface{}{ + "name": flattenDataSourceBackupDRBackupsName(original["name"], d, config), + "location": flattenDataSourceBackupDRBackupsLocation(original["location"], d, config), + "backup_id": flattenDataSourceBackupDRBackupsBackupId(original["backupId"], d, config), + "backup_vault_id": flattenDataSourceBackupDRBackupsBackupVaultId(original["backupVaultId"], d, config), + "data_source_id": flattenDataSourceBackupDRBackupsDataSourceId(original["dataSourceId"], d, config), + }) + } + return transformed +} + +func flattenDataSourceBackupDRBackupsName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataSourceBackupDRBackupsLocation(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataSourceBackupDRBackupsBackupId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataSourceBackupDRBackupsBackupVaultId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenDataSourceBackupDRBackupsDataSourceId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_test.go.tmpl b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_test.go.tmpl new file mode 100644 index 000000000000..ffa95639e75d --- /dev/null +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_test.go.tmpl @@ -0,0 +1,52 @@ +package backupdr_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccDataSourceGoogleCloudBackupDRBackup_basic(t *testing.T) { + t.Parallel() + + project := envvar.GetTestProjectFromEnv() + location := "us-central1" + backupVaultId := "bv-test" + dataSourceId := "ds-test" + + name := fmt.Sprintf("projects/%s/locations/%s/backupVaults/%s/dataSources/%s/backups", project, location, backupVaultId, dataSourceId) + + context := map[string]interface{}{ + "backup_vault_id": backupVaultId, + "data_source_id": dataSourceId, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleCloudBackupDRBackup_basic(context), + Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttr("data.google_backup_dr_backup.foo", "name", name)), + }, + }, + }) +} + +func testAccDataSourceGoogleCloudBackupDRBackup_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_project" "project" { +} + +data "google_backup_dr_backup" "foo" { + project = data.google_project.project.project_id + location = "us-central1" + backup_vault_id = "%{backup_vault_id}" + data_source_id = "%{data_source_id}" +} + +`, context) +} diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault.go b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault.go new file mode 100644 index 000000000000..5dba424ca2fe --- /dev/null +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault.go @@ -0,0 +1,48 @@ +package backupdr + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func DataSourceGoogleCloudBackupDRBackupVault() *schema.Resource { + + dsSchema := tpgresource.DatasourceSchemaFromResourceSchema(ResourceBackupDRBackupVault().Schema) + + tpgresource.AddRequiredFieldsToSchema(dsSchema, "backup_vault_id", "location") + + tpgresource.AddOptionalFieldsToSchema(dsSchema, "project") + + return &schema.Resource{ + Read: dataSourceGoogleCloudBackupDRBackupVaultRead, + Schema: dsSchema, + } +} + +func dataSourceGoogleCloudBackupDRBackupVaultRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + location, err := tpgresource.GetLocation(d, config) + if err != nil { + return err + } + backup_vault_id := d.Get("backup_vault_id").(string) + id := fmt.Sprintf("projects/%s/locations/%s/backupVaults/%s", project, location, backup_vault_id) + d.SetId(id) + err = resourceBackupDRBackupVaultRead(d, meta) + if err != nil { + return err + } + if d.Id() == "" { + return fmt.Errorf("%s not found", id) + } + + return nil +} diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault_test.go b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault_test.go new file mode 100644 index 000000000000..0aaf73d63ca9 --- /dev/null +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_backup_vault_test.go @@ -0,0 +1,51 @@ +package backupdr_test + +import ( + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "testing" +) + +func TestAccDataSourceGoogleBackupDRBackupVault_basic(t *testing.T) { + t.Parallel() + + random_suffix := acctest.RandString(t, 10) + context := map[string]interface{}{ + "random_suffix": random_suffix, + } + id := "tf-test-bv-" + random_suffix + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBackupDRBackupVaultDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleBackupDRBackupVault_basic(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.google_backup_dr_backup_vault.fetch-bv", "backup_vault_id", id), + ), + }, + }, + }) +} + +func testAccDataSourceGoogleBackupDRBackupVault_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_backup_dr_backup_vault" "test-bv" { + location = "us-central1" + backup_vault_id = "tf-test-bv-%{random_suffix}" + description = "This is a a backup vault built by Terraform." + backup_minimum_enforced_retention_duration = "100000s" + force_update = "true" + force_delete = "true" + allow_missing = "true" + ignore_backup_plan_references = "false" + ignore_inactive_datasources = "false" +} + +data "google_backup_dr_backup_vault" "fetch-bv" { + location = "us-central1" + backup_vault_id = google_backup_dr_backup_vault.test-bv.backup_vault_id +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source.go.tmpl b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source.go.tmpl index 32e498c5244f..1f477edfe4ee 100644 --- a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source.go.tmpl +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source.go.tmpl @@ -1,5 +1,4 @@ package backupdr -{{- if ne $.TargetVersionName "ga" }} import ( "fmt" @@ -619,4 +618,3 @@ func flattenBackupDRDataSourceDataSourceBackupApplianceApplicationApplicationHos func flattenBackupDRDataSourceDataSourceBackupApplianceApplicationApplicationHostId(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } -{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source_test.go.tmpl b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source_test.go.tmpl index dd08709e42c9..d2efbc74e2cc 100644 --- a/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source_test.go.tmpl +++ b/mmv1/third_party/terraform/services/backupdr/data_source_backup_dr_data_source_test.go.tmpl @@ -1,5 +1,4 @@ package backupdr_test -{{- if ne $.TargetVersionName "ga" }} import ( "fmt" @@ -54,4 +53,3 @@ data "google_backup_dr_data_source" "foo" { `, context) } -{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/beyondcorp/data_source_google_beyondcorp_app_connection_test.go b/mmv1/third_party/terraform/services/beyondcorp/data_source_google_beyondcorp_app_connection_test.go index 426be7d9bbfa..49c4057c5b3d 100644 --- a/mmv1/third_party/terraform/services/beyondcorp/data_source_google_beyondcorp_app_connection_test.go +++ b/mmv1/third_party/terraform/services/beyondcorp/data_source_google_beyondcorp_app_connection_test.go @@ -18,10 +18,7 @@ func TestAccDataSourceGoogleBeyondcorpAppConnection_basic(t *testing.T) { acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - ExternalProviders: map[string]resource.ExternalProvider{ - "time": {}, - }, - CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), + CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccDataSourceGoogleBeyondcorpAppConnection_basic(context), @@ -43,10 +40,7 @@ func TestAccDataSourceGoogleBeyondcorpAppConnection_full(t *testing.T) { acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - ExternalProviders: map[string]resource.ExternalProvider{ - "time": {}, - }, - CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), + CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccDataSourceGoogleBeyondcorpAppConnection_full(context), @@ -61,43 +55,34 @@ func TestAccDataSourceGoogleBeyondcorpAppConnection_full(t *testing.T) { func testAccDataSourceGoogleBeyondcorpAppConnection_basic(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_service_account" "service_account" { - account_id = "tf-test-my-account%{random_suffix}" - display_name = "Test Service Account" + account_id = "tf-test-my-account%{random_suffix}" + display_name = "Test Service Account" } -resource "time_sleep" "wait_120_seconds" { - depends_on = [google_service_account.service_account] - - create_duration = "120s" -} - - resource "google_beyondcorp_app_connector" "app_connector" { - depends_on = [time_sleep.wait_120_seconds] - - name = "tf-test-appconnector-%{random_suffix}" - principal_info { - service_account { - email = google_service_account.service_account.email - } - } + name = "tf-test-appconnector-%{random_suffix}" + principal_info { + service_account { + email = google_service_account.service_account.email + } + } } resource "google_beyondcorp_app_connection" "foo" { - name = "tf-test-my-app-connection-%{random_suffix}" - type = "TCP_PROXY" - application_endpoint { - host = "foo-host" - port = 8080 - } - connectors = [google_beyondcorp_app_connector.app_connector.id] - labels = { - my-label = "my-label-value" - } + name = "tf-test-my-app-connection-%{random_suffix}" + type = "TCP_PROXY" + application_endpoint { + host = "foo-host" + port = 8080 + } + connectors = [google_beyondcorp_app_connector.app_connector.id] + labels = { + my-label = "my-label-value" + } } data "google_beyondcorp_app_connection" "foo" { - name = google_beyondcorp_app_connection.foo.name + name = google_beyondcorp_app_connection.foo.name } `, context) } @@ -105,41 +90,33 @@ data "google_beyondcorp_app_connection" "foo" { func testAccDataSourceGoogleBeyondcorpAppConnection_full(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_service_account" "service_account" { - account_id = "tf-test-my-account%{random_suffix}" - display_name = "Test Service Account" -} - -resource "time_sleep" "wait_120_seconds" { - depends_on = [google_service_account.service_account] - - create_duration = "120s" + account_id = "tf-test-my-account%{random_suffix}" + display_name = "Test Service Account" } resource "google_beyondcorp_app_connector" "app_connector" { - depends_on = [time_sleep.wait_120_seconds] - - name = "tf-test-appconnector-%{random_suffix}" - principal_info { - service_account { - email = google_service_account.service_account.email - } - } + name = "tf-test-appconnector-%{random_suffix}" + principal_info { + service_account { + email = google_service_account.service_account.email + } + } } resource "google_beyondcorp_app_connection" "foo" { - name = "tf-test-my-app-connection-%{random_suffix}" - type = "TCP_PROXY" - application_endpoint { - host = "foo-host" - port = 8080 - } - connectors = [google_beyondcorp_app_connector.app_connector.id] + name = "tf-test-my-app-connection-%{random_suffix}" + type = "TCP_PROXY" + application_endpoint { + host = "foo-host" + port = 8080 + } + connectors = [google_beyondcorp_app_connector.app_connector.id] } data "google_beyondcorp_app_connection" "foo" { - name = google_beyondcorp_app_connection.foo.name - project = google_beyondcorp_app_connection.foo.project - region = google_beyondcorp_app_connection.foo.region + name = google_beyondcorp_app_connection.foo.name + project = google_beyondcorp_app_connection.foo.project + region = google_beyondcorp_app_connection.foo.region } `, context) } diff --git a/mmv1/third_party/terraform/services/beyondcorp/resource_beyondcorp_app_connection_test.go b/mmv1/third_party/terraform/services/beyondcorp/resource_beyondcorp_app_connection_test.go index 1a975d48eb40..dc666edf0855 100644 --- a/mmv1/third_party/terraform/services/beyondcorp/resource_beyondcorp_app_connection_test.go +++ b/mmv1/third_party/terraform/services/beyondcorp/resource_beyondcorp_app_connection_test.go @@ -17,10 +17,7 @@ func TestAccBeyondcorpAppConnection_beyondcorpAppConnectionUpdateExample(t *test acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - ExternalProviders: map[string]resource.ExternalProvider{ - "time": {}, - }, - CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), + CheckDestroy: testAccCheckBeyondcorpAppConnectionDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccBeyondcorpAppConnection_beyondcorpAppConnectionBasicExample(context), @@ -54,16 +51,7 @@ resource "google_service_account" "service_account" { display_name = "Test Service Account" } -resource "time_sleep" "wait_120_seconds" { - depends_on = [google_service_account.service_account] - - create_duration = "120s" -} - - resource "google_beyondcorp_app_connector" "app_connector" { - depends_on = [time_sleep.wait_120_seconds] - name = "tf-test-my-app-connector%{random_suffix}" principal_info { service_account { diff --git a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_meta.yaml b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_meta.yaml new file mode 100644 index 000000000000..a6f25b3dd093 --- /dev/null +++ b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_bigquery_table' +generation_type: 'handwritten' +api_service_name: 'bigquery.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'Table' diff --git a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_test.go b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_test.go index 484f1a21a21e..4c7198963057 100644 --- a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_test.go +++ b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_table_test.go @@ -902,7 +902,7 @@ func TestAccBigQueryExternalDataTable_queryAcceleration(t *testing.T) { connectionID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) metadataCacheMode := "AUTOMATIC" - // including an optional field. Should work without specifiying. + // including an optional field. Should work without specifying. // Has to follow google sql IntervalValue encoding maxStaleness := "0-0 0 10:0:0" @@ -927,7 +927,7 @@ func TestAccBigQueryExternalDataTable_objectTable(t *testing.T) { datasetID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) tableID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) connectionID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) - // including an optional field. Should work without specifiying. + // including an optional field. Should work without specifying. // Has to follow google sql IntervalValue encoding maxStaleness := "0-0 0 10:0:0" diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_app_profile_test.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_app_profile_test.go index 9966b499541d..f28ecdacf24f 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_app_profile_test.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_app_profile_test.go @@ -566,3 +566,99 @@ func TestAccBigtableAppProfile_updateStandardIsolationToDataBoost(t *testing.T) }, }) } + +func testAccBigtableAppProfile_updateRowAffinity(instanceName string) string { + return fmt.Sprintf(` +resource "google_bigtable_instance" "instance" { + name = "%s" + cluster { + cluster_id = "%s" + zone = "us-central1-b" + num_nodes = 1 + storage_type = "HDD" + } + cluster { + cluster_id = "%s2" + zone = "us-central1-a" + num_nodes = 1 + storage_type = "HDD" + } + cluster { + cluster_id = "%s3" + zone = "us-central1-c" + num_nodes = 1 + storage_type = "HDD" + } + deletion_protection = false +} +resource "google_bigtable_app_profile" "ap" { + instance = google_bigtable_instance.instance.id + app_profile_id = "test" + multi_cluster_routing_use_any = true + multi_cluster_routing_cluster_ids = ["%s", "%s2", "%s3"] + row_affinity = true + ignore_warnings = true +} +`, instanceName, instanceName, instanceName, instanceName, instanceName, instanceName, instanceName) +} + +func TestAccBigtableAppProfile_updateRowAffinity(t *testing.T) { + // bigtable instance does not use the shared HTTP client, this test creates an instance + acctest.SkipIfVcr(t) + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigtableAppProfileDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigtableAppProfile_updateMC2(instanceName), + }, + { + ResourceName: "google_bigtable_app_profile.ap", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_warnings"}, + }, + { + Config: testAccBigtableAppProfile_updateRowAffinity(instanceName), + }, + { + ResourceName: "google_bigtable_app_profile.ap", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_warnings"}, + }, + { + Config: testAccBigtableAppProfile_update1(instanceName), + }, + { + ResourceName: "google_bigtable_app_profile.ap", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_warnings"}, + }, + { + Config: testAccBigtableAppProfile_updateRowAffinity(instanceName), + }, + { + ResourceName: "google_bigtable_app_profile.ap", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_warnings"}, + }, + { + Config: testAccBigtableAppProfile_updateMC2(instanceName), + }, + { + ResourceName: "google_bigtable_app_profile.ap", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"ignore_warnings"}, + }, + }, + }) +} diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go index 7b431838426b..9168bcc380e4 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_internal_test.go @@ -18,7 +18,7 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { "empty subset view": { sv: bigtable.SubsetViewInfo{}, want: []map[string]interface{}{ - map[string]interface{}{}, + {}, }, orWant: nil, }, @@ -27,7 +27,7 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { RowPrefixes: [][]byte{[]byte("row1"), []byte("row2")}, }, want: []map[string]interface{}{ - map[string]interface{}{ + { "row_prefixes": []string{"cm93MQ==", "cm93Mg=="}, }, }, @@ -45,12 +45,12 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { }, }, want: []map[string]interface{}{ - map[string]interface{}{ + { "family_subsets": []map[string]interface{}{ - map[string]interface{}{ + { "family_name": "fam1", "qualifier_prefixes": []string{"Y29s"}, - }, map[string]interface{}{ + }, { "family_name": "fam2", "qualifiers": []string{"Y29sMQ==", "Y29sMg=="}, }, @@ -58,13 +58,13 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { }, }, orWant: []map[string]interface{}{ - map[string]interface{}{ + { "family_subsets": []map[string]interface{}{ - map[string]interface{}{ + { "family_name": "fam2", "qualifiers": []string{"Y29sMQ==", "Y29sMg=="}, }, - map[string]interface{}{ + { "family_name": "fam1", "qualifier_prefixes": []string{"Y29s"}, }, @@ -81,9 +81,9 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { }, }, want: []map[string]interface{}{ - map[string]interface{}{ + { "family_subsets": []map[string]interface{}{ - map[string]interface{}{ + { "family_name": "fam", "qualifiers": []string{"Y29s"}, }, @@ -101,9 +101,9 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { }, }, want: []map[string]interface{}{ - map[string]interface{}{ + { "family_subsets": []map[string]interface{}{ - map[string]interface{}{ + { "family_name": "fam", "qualifier_prefixes": []string{"Y29s"}, }, @@ -118,7 +118,7 @@ func TestUnitBigtable_flattenSubsetViewInfo(t *testing.T) { FamilySubsets: map[string]bigtable.FamilySubset{}, }, want: []map[string]interface{}{ - map[string]interface{}{}, + {}, }, orWant: nil, }, diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_meta.yaml b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_meta.yaml new file mode 100644 index 000000000000..2c112e2efd99 --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_authorized_view_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_bigtable_authorized_view' +generation_type: 'handwritten' +api_service_name: 'bigtableadmin.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'AuthorizedView' diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy.go index c9d710371664..dfad246c917d 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy.go @@ -402,7 +402,6 @@ func GcPolicyToGCRuleString(gc bigtable.GCPolicy, topLevel bool) (map[string]int } else { result["max_version"] = version } - break case bigtable.PolicyUnion: result["mode"] = "union" rules := []interface{}{} @@ -414,7 +413,6 @@ func GcPolicyToGCRuleString(gc bigtable.GCPolicy, topLevel bool) (map[string]int rules = append(rules, gcRuleString) } result["rules"] = rules - break case bigtable.PolicyIntersection: result["mode"] = "intersection" rules := []interface{}{} diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy_meta.yaml b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy_meta.yaml new file mode 100644 index 000000000000..8cf03dfc6636 --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_gc_policy_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_bigtable_gc_policy' +generation_type: 'handwritten' +api_service_name: 'bigtableadmin.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'Table' diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_internal_test.go b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_internal_test.go index acc71d2397bb..7490932c314b 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_internal_test.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_internal_test.go @@ -94,7 +94,7 @@ func TestUnitBigtable_getInstanceFromResponse(t *testing.T) { wantInstanceName: "", wantId: originalId, }, - "unavailble error": { + "unavailable error": { instanceNames: []string{"wrong", "also_wrong"}, listInstancesError: bigtable.ErrPartiallyUnavailable{[]string{"some", "location"}}, @@ -160,7 +160,7 @@ func TestUnitBigtable_flattenBigtableCluster(t *testing.T) { "kms_key_name": "KMS", "state": "CREATING", "autoscaling_config": []map[string]interface{}{ - map[string]interface{}{ + { "min_nodes": 3, "max_nodes": 7, "cpu_target": 50, diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_meta.yaml b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_meta.yaml new file mode 100644 index 000000000000..138640008a7e --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_instance_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_bigtable_instance' +generation_type: 'handwritten' +api_service_name: 'bigtableadmin.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'Instance' 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 3cd659cb58d7..453e68790a49 100644 --- a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table.go @@ -457,7 +457,7 @@ func resourceBigtableTableUpdate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error creating column family %q: %s", cfn, err) } } - for cfn, _ := range familyMapDiffKeys(oMap, nMap) { + for cfn := range familyMapDiffKeys(oMap, nMap) { log.Printf("[DEBUG] removing column family %q", cfn) if err := c.DeleteColumnFamily(ctx, name, cfn); err != nil { return fmt.Errorf("Error deleting column family %q: %s", cfn, err) diff --git a/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table_meta.yaml b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table_meta.yaml new file mode 100644 index 000000000000..48df86e47168 --- /dev/null +++ b/mmv1/third_party/terraform/services/bigtable/resource_bigtable_table_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_bigtable_table' +generation_type: 'handwritten' +api_service_name: 'bigtableadmin.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'Table' diff --git a/mmv1/third_party/terraform/services/cloudbuild/resource_cloudbuild_worker_pool_test.go.tmpl b/mmv1/third_party/terraform/services/cloudbuild/resource_cloudbuild_worker_pool_test.go.tmpl index 3497bf908742..6a32bb6f629a 100644 --- a/mmv1/third_party/terraform/services/cloudbuild/resource_cloudbuild_worker_pool_test.go.tmpl +++ b/mmv1/third_party/terraform/services/cloudbuild/resource_cloudbuild_worker_pool_test.go.tmpl @@ -57,9 +57,18 @@ func TestAccCloudbuildWorkerPool_withComputedAnnotations(t *testing.T) { func TestAccCloudbuildWorkerPool_basic(t *testing.T) { t.Parallel() + + testNetworkName := acctest.BootstrapSharedTestNetwork(t, "attachment-network") + subnetName := acctest.BootstrapSubnet(t, "tf-test-subnet", testNetworkName) + networkAttachmentName := acctest.BootstrapNetworkAttachment(t, "tf-test-attachment", subnetName) + + // Need to have the full network attachment name in the format project/{project_id}/regions/{region_id}/networkAttachments/{networkAttachmentName} + fullFormNetworkAttachmentName := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), networkAttachmentName) + context := map[string]interface{}{ "random_suffix": acctest.RandString(t, 10), "project": envvar.GetTestProjectFromEnv(), + "network_attachment": fullFormNetworkAttachmentName, } acctest.VcrTest(t, resource.TestCase{ @@ -106,6 +115,11 @@ resource "google_cloudbuild_worker_pool" "pool" { machine_type = "e2-standard-8" no_external_ip = true } + + private_service_connect { + network_attachment = "%{network_attachment}" + route_all_traffic = false + } } `, context) } @@ -164,9 +178,9 @@ func TestAccCloudbuildWorkerPool_withNetwork(t *testing.T) { t.Parallel() context := map[string]interface{}{ - "random_suffix": acctest.RandString(t, 10), - "project": envvar.GetTestProjectFromEnv(), - "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "cloudbuild-workerpool-1"), + "random_suffix": acctest.RandString(t, 10), + "project": envvar.GetTestProjectFromEnv(), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "cloudbuild-workerpool-1"), } acctest.VcrTest(t, resource.TestCase{ diff --git a/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_delivery_pipeline_meta copy.yaml b/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_delivery_pipeline_meta.yaml similarity index 100% rename from mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_delivery_pipeline_meta copy.yaml rename to mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_delivery_pipeline_meta.yaml diff --git a/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_target_test.go b/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_target_test.go index 881ab8ca3d5e..cba5e3d216f8 100644 --- a/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_target_test.go +++ b/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_target_test.go @@ -531,6 +531,19 @@ resource "google_clouddeploy_target" "primary" { my_first_label = "example-label-1" my_second_label = "example-label-2" } + + associated_entities { + entity_id = "test" + anthos_clusters { + membership = "projects/%{project_name}/locations/%{region}/memberships/membership-a" + } + + gke_clusters { + cluster = "projects/%{project_name}/locations/%{region}/clusters/cluster-a" + internal_ip = true + proxy_url = "http://10.0.0.1" + } + } } `, context) } diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go index afb8458f2974..06d96fa2b98e 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go @@ -911,7 +911,7 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro updateMaskArr = append(updateMaskArr, "buildEnvironmentVariables") } - if d.HasChange("vpc_connector") { + if d.HasChange("vpc_connector") || d.HasChange("vpc_connector_egress_settings") { function.VpcConnector = d.Get("vpc_connector").(string) updateMaskArr = append(updateMaskArr, "vpcConnector") } diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_meta.yaml b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_meta.yaml new file mode 100644 index 000000000000..02fe4c73ddb1 --- /dev/null +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_cloudfunctions_function' +generation_type: 'handwritten' +api_service_name: 'cloudfunctions.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Function' diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.tmpl b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.tmpl index e1f925ce86d2..6c8b5f76e133 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.tmpl +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.tmpl @@ -449,6 +449,45 @@ func TestAccCloudFunctionsFunction_vpcConnector(t *testing.T) { }) } +func TestAccCloudFunctionsFunction_vpcConnectorEgressSettings(t *testing.T) { + t.Parallel() + + funcResourceName := "google_cloudfunctions_function.function" + functionName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt(t)) + networkName := fmt.Sprintf("tf-test-net-%d", acctest.RandInt(t)) + vpcConnectorName := fmt.Sprintf("tf-test-conn-%s", acctest.RandString(t, 5)) + zipFilePath := acctest.CreateZIPArchiveForCloudFunctionSource(t, testHTTPTriggerPath) + projectNumber := os.Getenv("GOOGLE_PROJECT_NUMBER") + defer os.Remove(zipFilePath) // clean up + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckCloudFunctionsFunctionDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudFunctionsFunction_vpcConnectorEgressSettings(projectNumber, networkName, functionName, bucketName, zipFilePath, "10.10.0.0/28", vpcConnectorName, "PRIVATE_RANGES_ONLY"), + }, + { + ResourceName: funcResourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"build_environment_variables", "labels", "terraform_labels"}, + }, + { + Config: testAccCloudFunctionsFunction_vpcConnectorEgressSettings(projectNumber, networkName, functionName, bucketName, zipFilePath, "10.20.0.0/28", vpcConnectorName+"-update", "ALL_TRAFFIC"), + }, + { + ResourceName: funcResourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"build_environment_variables", "labels", "terraform_labels"}, + }, + }, + }) +} + func TestAccCloudFunctionsFunction_secretEnvVar(t *testing.T) { t.Parallel() @@ -707,7 +746,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" description = "test function" docker_registry = "ARTIFACT_REGISTRY" available_memory_mb = 128 @@ -756,7 +795,7 @@ resource "google_cloudfunctions_function" "function" { source_archive_object = google_storage_bucket_object.archive.name trigger_http = true https_trigger_security_level = "SECURE_ALWAYS" - runtime = "nodejs10" + runtime = "nodejs20" timeout = 91 entry_point = "helloGET" ingress_settings = "ALLOW_ALL" @@ -812,7 +851,7 @@ resource "google_cloudbuild_worker_pool" "pool" { resource "google_cloudfunctions_function" "function" { name = "%[3]s" - runtime = "nodejs10" + runtime = "nodejs20" description = "test function" docker_registry = "ARTIFACT_REGISTRY" available_memory_mb = 128 @@ -846,7 +885,7 @@ resource "google_pubsub_topic" "sub" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -883,7 +922,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -917,7 +956,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -948,7 +987,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -966,7 +1005,7 @@ func testAccCloudFunctionsFunction_sourceRepo(functionName, project string) stri return fmt.Sprintf(` resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" source_repository { // There isn't yet an API that'll allow us to create a source repository and @@ -1001,7 +1040,7 @@ data "google_compute_default_service_account" "default" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -1052,7 +1091,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" - runtime = "nodejs10" + runtime = "nodejs20" description = "test function" available_memory_mb = 128 @@ -1077,6 +1116,70 @@ resource "google_cloudfunctions_function" "function" { `, projectNumber, networkName, vpcConnectorName, vpcConnectorName, vpcIp, bucketName, zipFilePath, functionName, vpcConnectorName) } + +func testAccCloudFunctionsFunction_vpcConnectorEgressSettings(projectNumber, networkName, functionName, bucketName, zipFilePath, vpcIp, vpcConnectorName, vpcConnectorEgressSettings string) string { + return fmt.Sprintf(` +data "google_project" "project" {} + +resource "google_project_iam_member" "gcfadmin" { + project = data.google_project.project.project_id + role = "roles/editor" + member = "serviceAccount:service-%s@gcf-admin-robot.iam.gserviceaccount.com" +} + +resource "google_compute_network" "vpc" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_vpc_access_connector" "%s" { + name = "%s" + region = "us-central1" + ip_cidr_range = "%s" + network = google_compute_network.vpc.name + min_throughput = 200 + max_throughput = 300 +} + +resource "google_storage_bucket" "bucket" { + name = "%s" + location = "US" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "archive" { + name = "index.zip" + bucket = google_storage_bucket.bucket.name + source = "%s" +} + +resource "google_cloudfunctions_function" "function" { + name = "%s" + runtime = "nodejs20" + + description = "test function" + available_memory_mb = 128 + source_archive_bucket = google_storage_bucket.bucket.name + source_archive_object = google_storage_bucket_object.archive.name + trigger_http = true + timeout = 61 + entry_point = "helloGET" + labels = { + my-label = "my-label-value" + } + environment_variables = { + TEST_ENV_VARIABLE = "test-env-variable-value" + } + max_instances = 10 + min_instances = 3 + vpc_connector = google_vpc_access_connector.%s.self_link + vpc_connector_egress_settings = "%s" + + depends_on = [google_project_iam_member.gcfadmin] +} +`, projectNumber, networkName, vpcConnectorName, vpcConnectorName, vpcIp, bucketName, zipFilePath, functionName, vpcConnectorName, vpcConnectorEgressSettings) +} + {{ if ne $.TargetVersionName `ga` -}} func testAccCloudFunctionsFunction_docker_repository(arRepoName, functionName, bucketName, zipFilePath string) string { return fmt.Sprintf(` @@ -1113,7 +1216,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" description = "Function deployed to customer-provided Artifact Registry" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -1196,7 +1299,7 @@ resource "google_storage_bucket_object" "archive" { resource "google_cloudfunctions_function" "function" { name = "%s" description = "CMEK function" - runtime = "nodejs10" + runtime = "nodejs20" available_memory_mb = 128 source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name @@ -1395,7 +1498,7 @@ resource "time_sleep" "wait_iam_roles_%[3]s" { resource "google_cloudfunctions_function" "function" { depends_on = [time_sleep.wait_iam_roles_%[3]s] name = "%[5]s" - runtime = "nodejs10" + runtime = "nodejs20" source_archive_bucket = google_storage_bucket.bucket.name source_archive_object = google_storage_bucket_object.archive.name diff --git a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map.go.tmpl b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map.go.tmpl index 2f9ad0137118..a3aab2c8c184 100644 --- a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map.go.tmpl @@ -1,6 +1,5 @@ package composer -{{ if ne $.TargetVersionName `ga` -}} import ( "fmt" @@ -48,4 +47,3 @@ func dataSourceGoogleComposerUserWorkloadsConfigMapRead(d *schema.ResourceData, return nil } -{{- end }} diff --git a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map_test.go.tmpl b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map_test.go.tmpl index eac26bfd11cb..ea8e664c2773 100644 --- a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map_test.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_config_map_test.go.tmpl @@ -1,6 +1,5 @@ package composer_test -{{ if ne $.TargetVersionName `ga` -}} import ( "fmt" "testing" @@ -56,4 +55,3 @@ data "google_composer_user_workloads_config_map" "test" { } `, context) } -{{- end }} diff --git a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret.go.tmpl b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret.go.tmpl index 0acf758493bb..2e6575460548 100644 --- a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret.go.tmpl @@ -1,6 +1,5 @@ package composer -{{ if ne $.TargetVersionName `ga` -}} import ( "fmt" @@ -60,4 +59,3 @@ func dataSourceGoogleComposerUserWorkloadsSecretRead(d *schema.ResourceData, met return nil } -{{- end }} diff --git a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret_test.go.tmpl b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret_test.go.tmpl index 3860a8e8c40f..2098a4aeb89e 100644 --- a/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret_test.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/data_source_google_composer_user_workloads_secret_test.go.tmpl @@ -1,6 +1,5 @@ package composer_test -{{ if ne $.TargetVersionName `ga` -}} import ( "errors" "fmt" @@ -99,4 +98,3 @@ data "google_composer_user_workloads_secret" "test" { } `, context) } -{{- end }} diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.tmpl index e8da985580f1..7882a22c4566 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.tmpl @@ -56,9 +56,7 @@ var ( "config.0.software_config.0.python_version", "config.0.software_config.0.scheduler_count", "config.0.software_config.0.cloud_data_lineage_integration", -{{- if ne $.TargetVersionName "ga" }} "config.0.software_config.0.web_server_plugins_mode", -{{- end }} } composerConfigKeys = []string{ @@ -76,10 +74,8 @@ var ( "config.0.environment_size", "config.0.master_authorized_networks_config", "config.0.resilience_mode", -{{- if ne $.TargetVersionName "ga" }} "config.0.enable_private_environment", "config.0.enable_private_builds_only", -{{- end }} "config.0.data_retention_config", } @@ -92,9 +88,7 @@ var ( "config.0.workloads_config.0.triggerer", "config.0.workloads_config.0.web_server", "config.0.workloads_config.0.worker", -{{- if ne $.TargetVersionName "ga" }} "config.0.workloads_config.0.dag_processor", -{{- end }} } composerPrivateEnvironmentConfig = []string{ @@ -173,10 +167,8 @@ func ResourceComposerEnvironment() *schema.Resource { customdiff.ValidateChange("config.0.software_config.0.image_version", imageVersionChangeValidationFunc), versionValidationCustomizeDiffFunc, ), -{{- if ne $.TargetVersionName "ga" }} - customdiff.ForceNewIf("config.0.node_config.0.network", forceNewCustomDiff("config.0.node_config.0.network")), - customdiff.ForceNewIf("config.0.node_config.0.subnetwork", forceNewCustomDiff("config.0.node_config.0.subnetwork")), -{{- end }} + customdiff.ForceNewIf("config.0.node_config.0.network", forceNewIfNotComposer3CustomDiff("config.0.node_config.0.network")), + customdiff.ForceNewIf("config.0.node_config.0.subnetwork", forceNewIfNotComposer3CustomDiff("config.0.node_config.0.subnetwork")), ), Schema: map[string]*schema.Schema{ @@ -246,29 +238,18 @@ func ResourceComposerEnvironment() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, -{{- if eq $.TargetVersionName "ga" }} - ForceNew: true, -{{- else }} - ForceNew: false, ConflictsWith: []string{"config.0.node_config.0.composer_network_attachment"}, -{{- end }} DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, Description: `The Compute Engine machine type used for cluster instances, specified as a name or relative resource name. For example: "projects/{project}/zones/{zone}/machineTypes/{machineType}". Must belong to the enclosing environment's project and region/zone. The network must belong to the environment's project. If unspecified, the "default" network ID in the environment's project is used. If a Custom Subnet Network is provided, subnetwork must also be provided.`, }, "subnetwork": { Type: schema.TypeString, Optional: true, -{{- if eq $.TargetVersionName "ga" }} - ForceNew: true, -{{- else }} - ForceNew: false, Computed: true, ConflictsWith: []string{"config.0.node_config.0.composer_network_attachment"}, -{{- end }} DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, Description: `The Compute Engine subnetwork to be used for machine communications, specified as a self-link, relative resource name (e.g. "projects/{project}/regions/{region}/subnetworks/{subnetwork}"), or by name. If subnetwork is provided, network must also be provided and the subnetwork must belong to the enclosing environment's project and region.`, }, -{{- if ne $.TargetVersionName "ga" }} "composer_network_attachment": { Type: schema.TypeString, Computed: true, @@ -276,7 +257,6 @@ func ResourceComposerEnvironment() *schema.Resource { ForceNew: false, Description: `PSC (Private Service Connect) Network entry point. Customers can pre-create the Network Attachment and point Cloud Composer environment to use. It is possible to share network attachment among many environments, provided enough IP addresses are available.`, }, -{{- end }} "disk_size_gb": { Type: schema.TypeInt, Computed: true, @@ -385,7 +365,6 @@ func ResourceComposerEnvironment() *schema.Resource { }, }, }, -{{- if ne $.TargetVersionName "ga" }} "composer_internal_ipv4_cidr_block": { Type: schema.TypeString, Computed: true, @@ -394,7 +373,6 @@ func ResourceComposerEnvironment() *schema.Resource { ValidateFunc: validateComposerInternalIpv4CidrBlock, Description: `IPv4 cidr range that will be used by Composer internal components.`, }, -{{- end }} }, }, }, @@ -513,7 +491,6 @@ func ResourceComposerEnvironment() *schema.Resource { }, }, }, -{{- if ne $.TargetVersionName "ga" }} "web_server_plugins_mode": { Type: schema.TypeString, Optional: true, @@ -523,7 +500,6 @@ func ResourceComposerEnvironment() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"ENABLED", "DISABLED"}, false), Description: `Should be either 'ENABLED' or 'DISABLED'. Defaults to 'ENABLED'. Used in Composer 3.`, }, -{{- end }} }, }, }, @@ -606,7 +582,6 @@ func ResourceComposerEnvironment() *schema.Resource { }, }, }, -{{- if ne $.TargetVersionName "ga" }} "enable_private_environment": { Type: schema.TypeBool, Computed: true, @@ -623,7 +598,6 @@ func ResourceComposerEnvironment() *schema.Resource { AtLeastOneOf: composerConfigKeys, Description: `Optional. If true, builds performed during operations that install Python packages have only private connectivity to Google services. If false, the builds also have access to the internet.`, }, -{{- end }} "web_server_network_access_control": { Type: schema.TypeList, Optional: true, @@ -933,7 +907,6 @@ func ResourceComposerEnvironment() *schema.Resource { }, }, }, -{{- if ne $.TargetVersionName "ga" }} "dag_processor": { Type: schema.TypeList, Optional: true, @@ -979,7 +952,6 @@ func ResourceComposerEnvironment() *schema.Resource { }, }, }, -{{- end }} }, }, }, @@ -1225,7 +1197,6 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) return err } -{{ if ne $.TargetVersionName `ga` -}} noChangeErrorMessage := "Update request does not result in any change to the environment's configuration" if d.HasChange("config.0.node_config.0.network") || d.HasChange("config.0.node_config.0.subnetwork"){ // step 1: update with empty network and subnetwork @@ -1285,7 +1256,6 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) } } } -{{- end }} if d.HasChange("config.0.software_config.0.image_version") { patchObj := &composer.Environment{ @@ -1387,7 +1357,6 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) } } -{{ if ne $.TargetVersionName `ga` -}} if d.HasChange("config.0.enable_private_environment") { patchObj := &composer.Environment{ Config: &composer.EnvironmentConfig{ @@ -1429,7 +1398,6 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) return err } } -{{- end }} if d.HasChange("config.0.node_count") { patchObj := &composer.Environment{Config: &composer.EnvironmentConfig{}} @@ -1689,12 +1657,10 @@ func flattenComposerEnvironmentConfig(envCfg *composer.EnvironmentConfig) interf if !isComposer3(imageVersion){ transformed["private_environment_config"] = flattenComposerEnvironmentConfigPrivateEnvironmentConfig(envCfg.PrivateEnvironmentConfig) } -{{- if ne $.TargetVersionName "ga" }} if isComposer3(imageVersion) && envCfg.PrivateEnvironmentConfig != nil { transformed["enable_private_environment"] = envCfg.PrivateEnvironmentConfig.EnablePrivateEnvironment transformed["enable_private_builds_only"] = envCfg.PrivateEnvironmentConfig.EnablePrivateBuildsOnly } -{{- end }} transformed["web_server_network_access_control"] = flattenComposerEnvironmentConfigWebServerNetworkAccessControl(envCfg.WebServerNetworkAccessControl) transformed["database_config"] = flattenComposerEnvironmentConfigDatabaseConfig(envCfg.DatabaseConfig) transformed["web_server_config"] = flattenComposerEnvironmentConfigWebServerConfig(envCfg.WebServerConfig) @@ -1837,17 +1803,13 @@ func flattenComposerEnvironmentConfigWorkloadsConfig(workloadsConfig *composer.W transformedTriggerer := make(map[string]interface{}) transformedWebServer := make(map[string]interface{}) transformedWorker := make(map[string]interface{}) -{{- if ne $.TargetVersionName "ga" }} transformedDagProcessor := make(map[string]interface{}) -{{- end }} wlCfgScheduler := workloadsConfig.Scheduler wlCfgTriggerer := workloadsConfig.Triggerer wlCfgWebServer := workloadsConfig.WebServer wlCfgWorker := workloadsConfig.Worker -{{- if ne $.TargetVersionName "ga" }} wlCfgDagProcessor := workloadsConfig.DagProcessor -{{- end }} if wlCfgScheduler == nil { transformedScheduler = nil @@ -1884,7 +1846,6 @@ func flattenComposerEnvironmentConfigWorkloadsConfig(workloadsConfig *composer.W transformedWorker["max_count"] = wlCfgWorker.MaxCount } -{{ if ne $.TargetVersionName `ga` -}} if wlCfgDagProcessor == nil { transformedDagProcessor = nil } else { @@ -1893,7 +1854,6 @@ func flattenComposerEnvironmentConfigWorkloadsConfig(workloadsConfig *composer.W transformedDagProcessor["storage_gb"] = wlCfgDagProcessor.StorageGb transformedDagProcessor["count"] = wlCfgDagProcessor.Count } -{{- end }} transformed["scheduler"] = []interface{}{transformedScheduler} if transformedTriggerer != nil { @@ -1901,12 +1861,9 @@ func flattenComposerEnvironmentConfigWorkloadsConfig(workloadsConfig *composer.W } transformed["web_server"] = []interface{}{transformedWebServer} transformed["worker"] = []interface{}{transformedWorker} -{{- if ne $.TargetVersionName "ga" }} if transformedDagProcessor != nil { transformed["dag_processor"] = []interface{}{transformedDagProcessor} } -{{- end }} - return []interface{}{transformed} } @@ -1942,9 +1899,7 @@ func flattenComposerEnvironmentConfigNodeConfig(nodeCfg *composer.NodeConfig) in transformed["machine_type"] = nodeCfg.MachineType transformed["network"] = nodeCfg.Network transformed["subnetwork"] = nodeCfg.Subnetwork -{{- if ne $.TargetVersionName "ga" }} transformed["composer_network_attachment"] = nodeCfg.ComposerNetworkAttachment -{{- end }} transformed["disk_size_gb"] = nodeCfg.DiskSizeGb transformed["service_account"] = nodeCfg.ServiceAccount transformed["oauth_scopes"] = flattenComposerEnvironmentConfigNodeConfigOauthScopes(nodeCfg.OauthScopes) @@ -1954,9 +1909,7 @@ func flattenComposerEnvironmentConfigNodeConfig(nodeCfg *composer.NodeConfig) in transformed["enable_ip_masq_agent"] = nodeCfg.EnableIpMasqAgent transformed["tags"] = flattenComposerEnvironmentConfigNodeConfigTags(nodeCfg.Tags) transformed["ip_allocation_policy"] = flattenComposerEnvironmentConfigNodeConfigIPAllocationPolicy(nodeCfg.IpAllocationPolicy) -{{- if ne $.TargetVersionName "ga" }} transformed["composer_internal_ipv4_cidr_block"] = nodeCfg.ComposerInternalIpv4CidrBlock -{{- end }} return []interface{}{transformed} } @@ -2000,7 +1953,6 @@ func flattenComposerEnvironmentConfigSoftwareConfig(softwareCfg *composer.Softwa transformed["env_variables"] = softwareCfg.EnvVariables transformed["scheduler_count"] = softwareCfg.SchedulerCount transformed["cloud_data_lineage_integration"] = flattenComposerEnvironmentConfigSoftwareConfigCloudDataLineageIntegration(softwareCfg.CloudDataLineageIntegration) -{{- if ne $.TargetVersionName "ga" }} if softwareCfg.WebServerPluginsMode == "PLUGINS_DISABLED"{ transformed["web_server_plugins_mode"] = "DISABLED" } else if softwareCfg.WebServerPluginsMode == "PLUGINS_ENABLED"{ @@ -2008,7 +1960,6 @@ func flattenComposerEnvironmentConfigSoftwareConfig(softwareCfg *composer.Softwa } else { transformed["web_server_plugins_mode"] = softwareCfg.WebServerPluginsMode } -{{- end }} return []interface{}{transformed} } @@ -2078,7 +2029,6 @@ func expandComposerEnvironmentConfig(v interface{}, d *schema.ResourceData, conf } transformed.PrivateEnvironmentConfig = transformedPrivateEnvironmentConfig -{{ if ne $.TargetVersionName `ga` -}} /* config.enable_private_environment in terraform maps to composer.PrivateEnvironmentConfig.EnablePrivateEnvironment in API. @@ -2094,7 +2044,6 @@ func expandComposerEnvironmentConfig(v interface{}, d *schema.ResourceData, conf transformed.PrivateEnvironmentConfig.EnablePrivateBuildsOnly = enablePrivateBuildsOnlyRaw.(bool) } } -{{- end }} transformedWebServerNetworkAccessControl, err := expandComposerEnvironmentConfigWebServerNetworkAccessControl(original["web_server_network_access_control"], d, config) if err != nil { @@ -2393,7 +2342,6 @@ func expandComposerEnvironmentConfigWorkloadsConfig(v interface{}, d *schema.Res } } -{{ if ne $.TargetVersionName `ga` -}} if v, ok := original["dag_processor"]; ok { if len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { transformedDagProcessor := &composer.DagProcessorResource{} @@ -2405,7 +2353,6 @@ func expandComposerEnvironmentConfigWorkloadsConfig(v interface{}, d *schema.Res transformed.DagProcessor = transformedDagProcessor } } -{{- end }} return transformed, nil } @@ -2562,11 +2509,9 @@ func expandComposerEnvironmentConfigNodeConfig(v interface{}, d *schema.Resource transformed.Subnetwork = transformedSubnetwork } -{{ if ne $.TargetVersionName `ga` -}} if v, ok := original["composer_network_attachment"]; ok { transformed.ComposerNetworkAttachment = v.(string) } -{{- end }} transformedIPAllocationPolicy, err := expandComposerEnvironmentIPAllocationPolicy(original["ip_allocation_policy"], d, config) if err != nil { @@ -2586,11 +2531,9 @@ func expandComposerEnvironmentConfigNodeConfig(v interface{}, d *schema.Resource } transformed.Tags = transformedTags -{{ if ne $.TargetVersionName `ga` -}} if transformedComposerInternalIpv4CidrBlock, ok := original["composer_internal_ipv4_cidr_block"]; ok { transformed.ComposerInternalIpv4CidrBlock = transformedComposerInternalIpv4CidrBlock.(string) } -{{- end }} return transformed, nil } @@ -2741,7 +2684,6 @@ func expandComposerEnvironmentConfigSoftwareConfig(v interface{}, d *schema.Reso } transformed.CloudDataLineageIntegration = transformedCloudDataLineageIntegration -{{ if ne $.TargetVersionName `ga` -}} if original["web_server_plugins_mode"].(string) == "DISABLED"{ transformed.WebServerPluginsMode = "PLUGINS_DISABLED" } else if original["web_server_plugins_mode"].(string) == "ENABLED"{ @@ -2749,7 +2691,6 @@ func expandComposerEnvironmentConfigSoftwareConfig(v interface{}, d *schema.Reso } else { transformed.WebServerPluginsMode = original["web_server_plugins_mode"].(string) } -{{- end }} return transformed, nil } @@ -3047,7 +2988,7 @@ func isComposer3(imageVersion string) bool { return strings.Contains(imageVersion, "composer-3") } -func forceNewCustomDiff(key string) customdiff.ResourceConditionFunc { +func forceNewIfNotComposer3CustomDiff(key string) customdiff.ResourceConditionFunc { return func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool { old, new := d.GetChange(key) imageVersion := d.Get("config.0.software_config.0.image_version").(string) diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment_meta.yaml.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_environment_meta.yaml.tmpl new file mode 100644 index 000000000000..d7767c0a5855 --- /dev/null +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_composer_environment' +generation_type: 'handwritten' +api_service_name: 'composer.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'v1beta1' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Environment' diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.tmpl index 8fc8e27024b7..a236947c3b16 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.tmpl @@ -77,46 +77,6 @@ func TestAccComposerEnvironment_basic(t *testing.T) { }) } -// Checks that all updatable fields can be updated in one apply -// (PATCH for Environments only is per-field) -func TestAccComposerEnvironment_update(t *testing.T) { - // Currently failing - acctest.SkipIfVcr(t) - t.Parallel() - - envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) - network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) - subnetwork := network + "-1" - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccComposerEnvironment_basic(envName, network, subnetwork), - }, - { - Config: testAccComposerEnvironment_update(envName, network, subnetwork), - }, - { - ResourceName: "google_composer_environment.test", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, - }, - // This is a terrible clean-up step in order to get destroy to succeed, - // due to dangling firewall rules left by the Composer Environment blocking network deletion. - // TODO: Remove this check if firewall rules bug gets fixed by Composer. - { - PlanOnly: true, - ExpectNonEmptyPlan: false, - Config: testAccComposerEnvironment_update(envName, network, subnetwork), - Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), - }, - }, - }) -} // Checks private environment creation for composer 1 and 2. func TestAccComposerEnvironmentComposer1_private(t *testing.T) { @@ -280,46 +240,6 @@ func TestAccComposerEnvironment_withDatabaseConfig(t *testing.T) { }) } -func TestAccComposerEnvironment_withWebServerConfig(t *testing.T) { - // Currently failing - acctest.SkipIfVcr(t) - t.Parallel() - envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) - network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) - subnetwork := network + "-1" - - - grantServiceAgentsRole(t, "service-", []string{"gcp-sa-cloudbuild"}, "roles/cloudbuild.builds.builder") - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccComposerEnvironment_webServerCfg(envName, network, subnetwork), - }, - { - Config: testAccComposerEnvironment_webServerCfgUpdated(envName, network, subnetwork), - }, - { - ResourceName: "google_composer_environment.test", - ImportState: true, - ImportStateVerify: true, - }, - // This is a terrible clean-up step in order to get destroy to succeed, - // due to dangling firewall rules left by the Composer Environment blocking network deletion. - // TODO: Remove this check if firewall rules bug gets fixed by Composer. - { - PlanOnly: true, - ExpectNonEmptyPlan: false, - Config: testAccComposerEnvironment_webServerCfgUpdated(envName, network, subnetwork), - Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), - }, - }, - }) -} - func TestAccComposerEnvironment_withEncryptionConfigComposer1(t *testing.T) { t.Parallel() @@ -840,43 +760,6 @@ func TestAccComposerEnvironment_composerV2MasterAuthNetworksUpdate(t *testing.T) }) } -func TestAccComposer1Environment_withNodeConfig(t *testing.T) { - t.Parallel() - - envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) - network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) - subnetwork := network + "-1" - serviceAccount := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) - - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), - ExternalProviders: map[string]resource.ExternalProvider{ - "time": {}, - }, - Steps: []resource.TestStep{ - { - Config: testAccComposer1Environment_nodeCfg(envName, network, subnetwork, serviceAccount), - }, - { - ResourceName: "google_composer_environment.test", - ImportState: true, - ImportStateVerify: true, - }, - // This is a terrible clean-up step in order to get destroy to succeed, - // due to dangling firewall rules left by the Composer Environment blocking network deletion. - // TODO: Remove this check if firewall rules bug gets fixed by Composer. - { - PlanOnly: true, - ExpectNonEmptyPlan: false, - Config: testAccComposer1Environment_nodeCfg(envName, network, subnetwork, serviceAccount), - Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), - }, - }, - }) -} - func TestAccComposer2Environment_withNodeConfig(t *testing.T) { t.Parallel() @@ -1191,7 +1074,6 @@ func TestAccComposerEnvironment_customBucketWithUrl(t *testing.T) { }) } -{{ if ne $.TargetVersionName `ga` -}} // Checks Composer 3 environment creation with new fields. func TestAccComposerEnvironmentComposer3_basic(t *testing.T) { t.Parallel() @@ -1548,7 +1430,6 @@ func TestAccComposerEnvironmentComposer3_usesUnsupportedField_expectError(t *tes }, }) } -{{- end }} func testAccComposerEnvironment_customBucket(bucketName, envName, network, subnetwork string) string { return fmt.Sprintf(` @@ -1942,78 +1823,6 @@ resource "google_compute_subnetwork" "test" { `, name, network, subnetwork) } -func testAccComposerEnvironment_webServerCfg(name, network, subnetwork string) string { - return fmt.Sprintf(` -resource "google_composer_environment" "test" { - name = "%s" - region = "us-central1" - config { - node_config { - network = google_compute_network.test.self_link - subnetwork = google_compute_subnetwork.test.self_link - zone = "us-central1-a" - } - software_config { - image_version = "composer-1-airflow-2" - } - web_server_config { - machine_type = "composer-n1-webserver-4" - } - } -} - -// use a separate network to avoid conflicts with other tests running in parallel -// that use the default network/subnet -resource "google_compute_network" "test" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "test" { - name = "%s" - ip_cidr_range = "10.2.0.0/16" - region = "us-central1" - network = google_compute_network.test.self_link -} -`, name, network, subnetwork) -} - -func testAccComposerEnvironment_webServerCfgUpdated(name, network, subnetwork string) string { - return fmt.Sprintf(` -resource "google_composer_environment" "test" { - name = "%s" - region = "us-central1" - config { - node_config { - network = google_compute_network.test.self_link - subnetwork = google_compute_subnetwork.test.self_link - zone = "us-central1-a" - } - software_config { - image_version = "composer-1-airflow-2" - } - web_server_config { - machine_type = "composer-n1-webserver-8" - } - } -} - -// use a separate network to avoid conflicts with other tests running in parallel -// that use the default network/subnet -resource "google_compute_network" "test" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "test" { - name = "%s" - ip_cidr_range = "10.2.0.0/16" - region = "us-central1" - network = google_compute_network.test.self_link -} -`, name, network, subnetwork) -} - func testAccComposerEnvironment_encryptionCfg(pid, compVersion, airflowVersion, name, kmsKey, network, subnetwork string) string { return fmt.Sprintf(` data "google_project" "project" { @@ -2586,75 +2395,6 @@ resource "google_compute_subnetwork" "test" { `, envName, compVersion, airflowVersion, network, subnetwork) } - -func testAccComposerEnvironment_update(name, network, subnetwork string) string { - return fmt.Sprintf(` -resource "google_composer_environment" "test" { - name = "%s" - region = "us-central1" - - config { - node_count = 4 - node_config { - network = google_compute_network.test.self_link - subnetwork = google_compute_subnetwork.test.self_link - zone = "us-central1-a" - machine_type = "n1-standard-1" - ip_allocation_policy { - use_ip_aliases = true - cluster_ipv4_cidr_block = "10.0.0.0/16" - } - } - - software_config { - image_version = "composer-1-airflow-2" - - airflow_config_overrides = { - core-load_example = "True" - } - - pypi_packages = { - numpy = "" - } - - env_variables = { - FOO = "bar" - } - } -{{- if ne $.TargetVersionName "ga" }} - web_server_config { - machine_type = "composer-n1-webserver-4" - } - - database_config { - machine_type = "db-n1-standard-4" - } -{{- end }} - } - - labels = { - foo = "bar" - anotherlabel = "boo" - } -} - -// use a separate network to avoid conflicts with other tests running in parallel -// that use the default network/subnet -resource "google_compute_network" "test" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "test" { - name = "%s" - ip_cidr_range = "10.2.0.0/16" - region = "us-central1" - network = google_compute_network.test.self_link -} -`, name, network, subnetwork) -} - - func testAccComposerEnvironment_updateComposerV2(name, network, subnetwork string) string { return fmt.Sprintf(` resource "google_composer_environment" "test" { @@ -2733,69 +2473,6 @@ resource "google_compute_subnetwork" "test" { `, name, network, subnetwork) } -func testAccComposer1Environment_nodeCfg(environment, network, subnetwork, serviceAccount string) string { - return fmt.Sprintf(` -data "google_project" "project" {} - -resource "google_composer_environment" "test" { - name = "%s" - region = "us-central1" - config { - node_config { - network = google_compute_network.test.self_link - subnetwork = google_compute_subnetwork.test.self_link - zone = "us-central1-a" - - service_account = google_service_account.test.name -{{- if ne $.TargetVersionName "ga" }} - max_pods_per_node = 33 -{{- end }} - ip_allocation_policy { - use_ip_aliases = true - cluster_ipv4_cidr_block = "10.0.0.0/16" - } - tags = toset(["t1", "t2"]) - machine_type = "n2-highcpu-2" - disk_size_gb = 20 - oauth_scopes = toset(["https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/bigquery"]) - } - software_config { - image_version = "composer-1-airflow-2" - } - } - depends_on = [time_sleep.wait_3_minutes] -} - -resource "google_compute_network" "test" { - name = "%s" - auto_create_subnetworks = false -} - -resource "google_compute_subnetwork" "test" { - name = "%s" - ip_cidr_range = "10.2.0.0/16" - region = "us-central1" - network = google_compute_network.test.self_link -} - -resource "time_sleep" "wait_3_minutes" { - depends_on = [google_project_iam_member.composer-worker] - create_duration = "3m" -} - -resource "google_service_account" "test" { - account_id = "%s" - display_name = "Test Service Account for Composer Environment" -} - -resource "google_project_iam_member" "composer-worker" { - project = data.google_project.project.project_id - role = "roles/composer.worker" - member = "serviceAccount:${google_service_account.test.email}" -} -`, environment, network, subnetwork, serviceAccount) -} - func testAccComposer2Environment_nodeCfg(environment, network, subnetwork, serviceAccount string) string { return fmt.Sprintf(` data "google_project" "project" {} @@ -3233,7 +2910,6 @@ resource "google_project_iam_member" "composer-worker" { `, environment, network, subnetwork, serviceAccount) } -{{ if ne $.TargetVersionName `ga` -}} func testAccComposerEnvironmentComposer2_empty(name, network, subnetwork string) string { return fmt.Sprintf(` resource "google_composer_environment" "test" { @@ -3302,7 +2978,7 @@ resource "google_composer_environment" "test" { config { software_config { image_version = "composer-2-airflow-2" - web_server_plugins_mode = "ENABLED" + web_server_plugins_mode = "ENABLED" } } } @@ -3573,7 +3249,6 @@ resource "google_compute_subnetwork" "test" { } `, name, networkAttachment, network, subnetwork) } -{{- end }} // WARNING: This is not actually a check and is a terrible clean-up step because Composer Environments // have a bug that hasn't been fixed. Composer will add firewalls to non-default networks for environments diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_config_map_test.go.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_config_map_test.go.tmpl index 312d8331f75b..37feb346b799 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_config_map_test.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_config_map_test.go.tmpl @@ -1,7 +1,5 @@ package composer_test -{{ if ne $.TargetVersionName `ga` -}} - import ( "fmt" "strings" @@ -22,7 +20,7 @@ func TestAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicEx acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckComposerUserWorkloadsConfigMapDestroyProducer(t), Steps: []resource.TestStep{ { @@ -58,7 +56,7 @@ func TestAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicEx acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckComposerUserWorkloadsConfigMapDestroyProducer(t), Steps: []resource.TestStep{ { @@ -82,7 +80,6 @@ func TestAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicEx func testAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicExample_basic(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_composer_environment" "environment" { - provider = google-beta name = "tf-test-test-environment%{random_suffix}" region = "us-central1" config { @@ -93,7 +90,6 @@ resource "google_composer_environment" "environment" { } resource "google_composer_user_workloads_config_map" "config_map" { - provider = google-beta name = "tf-test-test-config-map%{random_suffix}" region = "us-central1" environment = google_composer_environment.environment.name @@ -107,7 +103,6 @@ resource "google_composer_user_workloads_config_map" "config_map" { func testAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicExample_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_composer_environment" "environment" { - provider = google-beta name = "tf-test-test-environment%{random_suffix}" region = "us-central1" config { @@ -118,7 +113,6 @@ resource "google_composer_environment" "environment" { } resource "google_composer_user_workloads_config_map" "config_map" { - provider = google-beta name = "tf-test-test-config-map%{random_suffix}" region = "us-central1" environment = google_composer_environment.environment.name @@ -132,7 +126,6 @@ resource "google_composer_user_workloads_config_map" "config_map" { func testAccComposerUserWorkloadsConfigMap_composerUserWorkloadsConfigMapBasicExample_delete(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_composer_environment" "environment" { - provider = google-beta name = "tf-test-test-environment%{random_suffix}" region = "us-central1" config { @@ -166,5 +159,3 @@ func testAccComposerUserWorkloadsConfigMapDestroyed(t *testing.T) func(s *terraf return nil } } - -{{ end }} diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret.go.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret.go.tmpl index 94ebd8182ebc..9cea9a079dbb 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret.go.tmpl @@ -1,7 +1,5 @@ package composer -{{ if ne $.TargetVersionName `ga` -}} - import ( "fmt" "log" @@ -267,5 +265,3 @@ func (n *UserWorkloadsSecretName) ResourceName() string { func (n *UserWorkloadsSecretName) ParentName() string { return fmt.Sprintf("projects/%s/locations/%s/environments/%s", n.Project, n.Region, n.Environment) } - -{{ end }} diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_meta.yaml.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_meta.yaml.tmpl new file mode 100644 index 000000000000..d4de6ac21601 --- /dev/null +++ b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_composer_user_workloads_secret' +generation_type: 'handwritten' +api_service_name: 'composer.googleapis.com' +api_version: 'v1beta1' +api_resource_type_kind: 'UserWorkloadsSecret' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_test.go.tmpl b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_test.go.tmpl index 9008bfdc65df..cb83e29ce0d0 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_test.go.tmpl +++ b/mmv1/third_party/terraform/services/composer/resource_composer_user_workloads_secret_test.go.tmpl @@ -1,7 +1,5 @@ package composer_test -{{ if ne $.TargetVersionName `ga` -}} - import ( "fmt" "testing" @@ -179,5 +177,3 @@ func testAccComposerUserWorkloadsSecretDestroyed(t *testing.T) func(s *terraform return nil } } - -{{ end }} diff --git a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl index 24ab6bedb307..5a5267ab8eab 100644 --- a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl @@ -515,7 +515,7 @@ func expandNetworkInterfaces(d tpgresource.TerraformResourceData, config *transp if networkAttachmentObj, ok := data["network_attachment"]; ok { networkAttachment = networkAttachmentObj.(string) } - // Checks if networkAttachment is not specified in resource, network or subnetwork have to be specifed. + // Checks if networkAttachment is not specified in resource, network or subnetwork have to be specified. if networkAttachment == "" && network == "" && subnetwork == "" { return nil, fmt.Errorf("exactly one of network, subnetwork, or network_attachment must be provided") } @@ -665,6 +665,7 @@ func expandAdvancedMachineFeatures(d tpgresource.TerraformResourceData) *compute TurboMode: d.Get(prefix + ".turbo_mode").(string), VisibleCoreCount: int64(d.Get(prefix + ".visible_core_count").(int)), PerformanceMonitoringUnit: d.Get(prefix + ".performance_monitoring_unit").(string), + EnableUefiNetworking: d.Get(prefix + ".enable_uefi_networking").(bool), } } @@ -678,6 +679,7 @@ func flattenAdvancedMachineFeatures(AdvancedMachineFeatures *compute.AdvancedMac "turbo_mode": AdvancedMachineFeatures.TurboMode, "visible_core_count": AdvancedMachineFeatures.VisibleCoreCount, "performance_monitoring_unit": AdvancedMachineFeatures.PerformanceMonitoringUnit, + "enable_uefi_networking": AdvancedMachineFeatures.EnableUefiNetworking, {{"}}"}} } diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_network.go.tmpl b/mmv1/third_party/terraform/services/compute/data_source_google_compute_network.go.tmpl index 2e3d521ac945..da19428452ad 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_network.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_network.go.tmpl @@ -2,6 +2,7 @@ package compute import ( "fmt" + "strconv" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-google/google/tpgresource" @@ -23,6 +24,14 @@ func DataSourceGoogleComputeNetwork() *schema.Resource { Computed: true, }, + // TODO: this should eventually be TypeInt, but leaving as + // string for now to match the resource and to avoid a + // breaking change. + "numeric_id": { + Type: schema.TypeString, + Computed: true, + }, + "gateway_ipv4": { Type: schema.TypeString, Computed: true, @@ -95,6 +104,9 @@ func dataSourceGoogleComputeNetworkRead(d *schema.ResourceData, meta interface{} if err := d.Set("description", network.Description); err != nil { return fmt.Errorf("Error setting description: %s", err) } + if err := d.Set("numeric_id", strconv.Itoa(int(network.Id))); err != nil { + return fmt.Errorf("Error setting numeric_id: %s", err) + } if err := d.Set("subnetworks_self_links", network.Subnetworks); err != nil { return fmt.Errorf("Error setting subnetworks_self_links: %s", err) } diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_network_test.go b/mmv1/third_party/terraform/services/compute/data_source_google_compute_network_test.go index 53b4d5152553..d54970e576a7 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_network_test.go +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_network_test.go @@ -45,6 +45,7 @@ func testAccDataSourceGoogleNetworkCheck(data_source_name string, resource_name network_attrs_to_test := []string{ "id", "name", + "numeric_id", "description", "internal_ipv6_range", } diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork.go.tmpl b/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork.go.tmpl index 4315751f0b08..cfd54e7e8895 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork.go.tmpl @@ -31,6 +31,10 @@ func DataSourceGoogleComputeSubnetwork() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "subnetwork_id": { + Type: schema.TypeInt, + Computed: true, + }, "ip_cidr_range": { Type: schema.TypeString, Computed: true, @@ -100,6 +104,10 @@ func dataSourceGoogleComputeSubnetworkRead(d *schema.ResourceData, meta interfac return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("Subnetwork Not Found : %s", name), id) } + if err := d.Set("subnetwork_id", subnetwork.Id); err != nil { + return fmt.Errorf("Error setting subnetwork_id: %s", err) + } + if err := d.Set("ip_cidr_range", subnetwork.IpCidrRange); err != nil { return fmt.Errorf("Error setting ip_cidr_range: %s", err) } diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork_test.go b/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork_test.go index 4b7f39a5979a..a2e2d293c8c8 100644 --- a/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork_test.go +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_subnetwork_test.go @@ -47,6 +47,7 @@ func testAccDataSourceGoogleSubnetworkCheck(data_source_name string, resource_na "id", "name", "description", + "subnetwork_id", "ip_cidr_range", "private_ip_google_access", "internal_ipv6_prefix", diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_attached_disk_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_attached_disk_meta.yaml.tmpl new file mode 100644 index 000000000000..44e33adea27b --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_attached_disk_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_attached_disk' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Instance' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_disk_async_replication_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_disk_async_replication_meta.yaml.tmpl new file mode 100644 index 000000000000..cdf1e3eeea2b --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_disk_async_replication_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_disk_async_replication' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Disk' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_disk_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_disk_test.go.tmpl index 4bbbe5e29b69..b3bc5a8b267d 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_disk_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_disk_test.go.tmpl @@ -10,6 +10,8 @@ import ( "github.com/hashicorp/terraform-provider-google/google/acctest" "github.com/hashicorp/terraform-provider-google/google/envvar" tpgcompute "github.com/hashicorp/terraform-provider-google/google/services/compute" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" {{ if eq $.TargetVersionName `ga` }} "google.golang.org/api/compute/v1" @@ -1632,6 +1634,28 @@ func TestAccComputeDisk_storagePoolSpecified(t *testing.T) { }) } +func TestAccComputeDisk_storagePoolSpecified_nameOnly(t *testing.T) { + t.Parallel() + + acctest.BootstrapComputeStoragePool(t, "basic-2", "hyperdisk-throughput") + diskName := fmt.Sprintf("tf-test-disk-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeDisk_storagePoolSpecified(diskName, "tf-bootstrap-storage-pool-hyperdisk-throughput-basic-2"), + }, + { + ResourceName: "google_compute_disk.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeDisk_storagePoolSpecified(diskName, storagePoolUrl string) string { return fmt.Sprintf(` resource "google_compute_disk" "foobar" { @@ -1644,6 +1668,189 @@ resource "google_compute_disk" "foobar" { `, diskName, storagePoolUrl) } +func TestExpandStoragePoolUrl_withDataProjectAndZone(t *testing.T) { + config := &transport_tpg.Config{ + ComputeBasePath: "https://www.googleapis.com/compute/v1/", + Project: "other-project", + Zone: "other-zone", + } + + data := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": "test-project", + "zone": "test-zone", + }, + } + + name := "test-storage-pool" + zoneUrl := "zones/test-zone/storagePools/" + name + projectUrl := "projects/test-project/" + zoneUrl + fullUrl := config.ComputeBasePath + projectUrl + + cases := []struct { + name string + inputStr string + }{ + { + name: "full url", + inputStr: fullUrl, + }, + { + name: "project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: projectUrl, + }, + { + name: "/project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + projectUrl, + }, + { + name: "zones/{zone}/storagePools/{storagePool}", + inputStr: zoneUrl, + }, + { + name: "/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + zoneUrl, + }, + { + name: "{storagePool}", + inputStr: name, + }, + { + name: "/{storagePool}", + inputStr: "/" + name, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + result, _ := tpgcompute.ExpandStoragePoolUrl(tc.inputStr, data, config) + if result != fullUrl { + t.Fatalf("%s does not match with expected full url: %s", result, fullUrl) + } + }) + } +} + +func TestExpandStoragePoolUrl_withConfigProjectAndZone(t *testing.T) { + config := &transport_tpg.Config{ + ComputeBasePath: "https://www.googleapis.com/compute/v1/", + Project: "test-project", + Zone: "test-zone", + } + + data := &tpgresource.ResourceDataMock{} + + name := "test-storage-pool" + zoneUrl := "zones/test-zone/storagePools/" + name + projectUrl := "projects/test-project/" + zoneUrl + fullUrl := config.ComputeBasePath + projectUrl + + cases := []struct { + name string + inputStr string + }{ + { + name: "full url", + inputStr: fullUrl, + }, + { + name: "project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: projectUrl, + }, + { + name: "/project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + projectUrl, + }, + { + name: "zones/{zone}/storagePools/{storagePool}", + inputStr: zoneUrl, + }, + { + name: "/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + zoneUrl, + }, + { + name: "{storagePool}", + inputStr: name, + }, + { + name: "/{storagePool}", + inputStr: "/" + name, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + result, _ := tpgcompute.ExpandStoragePoolUrl(tc.inputStr, data, config) + if result != fullUrl { + t.Fatalf("%s does not match with expected full url: %s", result, fullUrl) + } + }) + } +} + +func TestExpandStoragePoolUrl_noProjectAndZoneFromConfigAndData(t *testing.T) { + config := &transport_tpg.Config{ + ComputeBasePath: "https://www.googleapis.com/compute/v1/", + } + + data := &tpgresource.ResourceDataMock{} + + name := "test-storage-pool" + zoneUrl := "zones/test-zone/storagePools/" + name + projectUrl := "projects/test-project/" + zoneUrl + fullUrl := config.ComputeBasePath + projectUrl + + cases := []struct { + name string + inputStr string + }{ + { + name: "full url", + inputStr: fullUrl, + }, + { + name: "project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: projectUrl, + }, + { + name: "/project/{project}/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + projectUrl, + }, + { + name: "zones/{zone}/storagePools/{storagePool}", + inputStr: zoneUrl, + }, + { + name: "/zones/{zone}/storagePools/{storagePool}", + inputStr: "/" + zoneUrl, + }, + { + name: "{storagePool}", + inputStr: name, + }, + { + name: "/{storagePool}", + inputStr: "/" + name, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + _, err := tpgcompute.ExpandStoragePoolUrl(tc.inputStr, data, config) + if err == nil { + t.Fatal("Should return error when no project and zone available from config or resource data") + } + }) + } +} + func TestAccComputeDisk_accessModeSpecified(t *testing.T) { t.Parallel() diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_firewall_policy_association_meta.yaml b/mmv1/third_party/terraform/services/compute/resource_compute_firewall_policy_association_meta.yaml new file mode 100644 index 000000000000..ab69c8c5b7ce --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_firewall_policy_association_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_compute_firewall_policy_association' +generation_type: 'dcl' +api_service_name: 'compute.googleapis.com' +api_version: 'beta' +api_resource_type_kind: 'FirewallPolicy' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl index 8e6b5383123e..57fa41af26f5 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl @@ -60,6 +60,7 @@ var ( "advanced_machine_features.0.turbo_mode", "advanced_machine_features.0.visible_core_count", "advanced_machine_features.0.performance_monitoring_unit", + "advanced_machine_features.0.enable_uefi_networking", } bootDiskKeys = []string{ @@ -217,7 +218,6 @@ func ResourceComputeInstance() *schema.Resource { Optional: true, AtLeastOneOf: bootDiskKeys, Default: true, - ForceNew: true, Description: `Whether the disk will be auto-deleted when the instance is deleted.`, }, @@ -535,7 +535,7 @@ func ResourceComputeInstance() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6", "IPV6_ONLY", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6", ""}, false), Description: `The stack type for this network interface to identify whether the IPv6 feature is enabled or not. If not specified, IPV4_ONLY will be used.`, }, @@ -547,8 +547,7 @@ func ResourceComputeInstance() *schema.Resource { "ipv6_access_config": { Type: schema.TypeList, - Optional: true, - Computed: true, + Optional: true, Description: `An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig specified, then this instance will have no external IPv6 Internet access.`, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -816,7 +815,6 @@ func ResourceComputeInstance() *schema.Resource { "metadata_startup_script": { Type: schema.TypeString, Optional: true, - ForceNew: true, Description: `Metadata startup scripts made available within the instance.`, }, @@ -1134,6 +1132,13 @@ be from 0 to 999,999,999 inclusive.`, ValidateFunc: validation.StringInSlice([]string{"STANDARD", "ENHANCED", "ARCHITECTURAL"}, false), Description: `The PMU is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are "STANDARD", "ENHANCED", and "ARCHITECTURAL".`, }, + "enable_uefi_networking": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + AtLeastOneOf: advancedMachineFeaturesKeys, + Description: `Whether to enable UEFI networking for the instance.`, + }, }, }, }, @@ -1316,6 +1321,9 @@ be from 0 to 999,999,999 inclusive.`, }, suppressEmptyGuestAcceleratorDiff, ), + customdiff.ForceNewIf("metadata_startup_script", func(_ context.Context, d *schema.ResourceDiff, meta interface{}) bool { + return isGracefulMetadataStartupSwitch(d) + }), validateSubnetworkProject, forceNewIfNetworkIPNotUpdatable, tpgresource.SetLabelsDiff, @@ -2495,6 +2503,18 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + // if any other boot_disk fields will be added here this should be wrapped in if d.HasChange("boot_disk") + if d.HasChange("boot_disk.0.auto_delete") { + op, err := config.NewComputeClient(userAgent).Instances.SetDiskAutoDelete(project, zone, instance.Name, d.Get("boot_disk.0.auto_delete").(bool), d.Get("boot_disk.0.device_name").(string)).Do() + if err != nil { + return fmt.Errorf("Error changing auto_delete: %s", err) + } + opErr := ComputeOperationWaitTime(config, op, project, "changing auto_delete", userAgent, d.Timeout(schema.TimeoutUpdate)) + if opErr != nil { + return opErr + } + } + // d.HasChange("service_account") is oversensitive: see https://github.com/hashicorp/terraform/issues/17411 // Until that's fixed, manually check whether there is a change. o, n := d.GetChange("service_account") @@ -2978,6 +2998,52 @@ func suppressEmptyGuestAcceleratorDiff(_ context.Context, d *schema.ResourceDiff return nil } +// Function checks whether a graceful switch (without ForceNew) is available +// between `metadata_startup_script` and `metadata.startup-script`. +// Graceful switch can be executed in two situations: +// 1. When `metadata_startup_script` is created with the old value of +// `metadata.startup-script`. +// 2. When `metadata_startup_script` is deleted and the old value remains in +// `metadata.startup-script` +// For all other changes in `metadata_startup_script`, function sets ForceNew. +func isGracefulMetadataStartupSwitch(d *schema.ResourceDiff) bool { + oldMd, newMd := d.GetChange("metadata") + oldMdMap := oldMd.(map[string]interface{}) + newMdMap := newMd.(map[string]interface{}) + + //No new and old metadata + if len(oldMdMap) == 0 && len(newMdMap) == 0 { + return true + } + + oldMds, newMds := d.GetChange("metadata_startup_script") + vMdOld, okOld := oldMdMap["startup-script"] + vMdNew, okNew := newMdMap["startup-script"] + + // metadata_startup_script is created + if oldMds == "" { + if !okOld { + return true + } else if newMds == vMdOld { + return false + } else { + return true + } + } + // metadata_startup_script is deleted + if newMds == "" { + if !okNew { + return true + } else if oldMds == vMdNew { + return false + } else { + return true + } + } + + return true +} + func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*transport_tpg.Config) userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) @@ -3153,7 +3219,11 @@ func expandBootDisk(d *schema.ResourceData, config *transport_tpg.Config, projec } if v, ok := d.GetOk("boot_disk.0.initialize_params.0.storage_pool"); ok { - disk.InitializeParams.StoragePool = v.(string) + storagePoolUrl, err := expandStoragePool(v, d, config) + if err != nil { + return nil, fmt.Errorf("Error resolving storage pool name '%s': '%s'", v.(string), err) + } + disk.InitializeParams.StoragePool = storagePoolUrl.(string) } } @@ -3252,6 +3322,10 @@ func flattenScratchDisk(disk *compute.AttachedDisk) map[string]interface{} { return result } +func expandStoragePool(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return ExpandStoragePoolUrl(v, d, config) +} + func hash256(raw string) (string, error) { decoded, err := base64.StdEncoding.DecodeString(raw) if err != nil { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image_meta.yaml.tmpl new file mode 100644 index 000000000000..3d78830f6860 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_machine_image_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_compute_instance_from_machine_image' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +api_version: 'beta' +api_resource_type_kind: 'Instance' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template_meta.yaml.tmpl new file mode 100644 index 000000000000..9318469eea6c --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_from_template_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_instance_from_template' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Instance' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_meta.yaml.tmpl new file mode 100644 index 000000000000..7160be228f93 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_instance_group_manager' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'InstanceGroupManager' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_meta.yaml.tmpl new file mode 100644 index 000000000000..855829b72300 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_instance_group' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'InstanceGroup' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_meta.yaml.tmpl new file mode 100644 index 000000000000..6d3c8772c774 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_instance' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Instance' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl index 0417877868e4..d9dcd5ad55e9 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl @@ -555,7 +555,7 @@ Google Cloud KMS.`, Optional: true, Computed: true, ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6", "IPV6_ONLY", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6", ""}, false), Description: `The stack type for this network interface to identify whether the IPv6 feature is enabled or not. If not specified, IPV4_ONLY will be used.`, }, @@ -569,7 +569,6 @@ Google Cloud KMS.`, "ipv6_access_config": { Type: schema.TypeList, Optional: true, - Computed: true, ForceNew: true, Description: `An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig specified, then this instance will have no external IPv6 Internet access.`, Elem: &schema.Resource{ @@ -989,6 +988,12 @@ be from 0 to 999,999,999 inclusive.`, ValidateFunc: validation.StringInSlice([]string{"STANDARD", "ENHANCED", "ARCHITECTURAL"}, false), Description: `The PMU is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are "STANDARD", "ENHANCED", and "ARCHITECTURAL".`, }, + "enable_uefi_networking": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: `Whether to enable UEFI networking or not.`, + }, }, }, }, diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_meta.yaml.tmpl new file mode 100644 index 000000000000..cd87c8db0e30 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_instance_template' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'InstanceTemplate' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl index ab19e4c725b5..85549bc4c1a4 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl @@ -963,6 +963,47 @@ func TestAccComputeInstanceTemplate_performanceMonitoringUnit(t *testing.T) { }) } +func TestAccComputeInstanceTemplate_enableUefiNetworking(t *testing.T) { + t.Parallel() + + var instanceTemplate compute.InstanceTemplate + context_1 := map[string]interface{}{ + "instance_name": fmt.Sprintf("tf-test-instance-template-%s", acctest.RandString(t, 10)), + "enable_uefi_networking": "false", + } + context_2 := map[string]interface{}{ + "instance_name": context_1["instance_name"].(string), + "enable_uefi_networking": "true", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstanceTemplate_enableUefiNetworking(context_1), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceTemplateExists(t, "google_compute_instance_template.foobar", &instanceTemplate), + resource.TestCheckResourceAttr("google_compute_instance_template.foobar", "advanced_machine_features.0.enable_uefi_networking", "false"), + ), + }, + { + Config: testAccComputeInstanceTemplate_enableUefiNetworking(context_2), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceTemplateExists(t, "google_compute_instance_template.foobar", &instanceTemplate), + resource.TestCheckResourceAttr("google_compute_instance_template.foobar", "advanced_machine_features.0.enable_uefi_networking", "true"), + ), + }, + { + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + {{ if ne $.TargetVersionName `ga` -}} func TestAccComputeInstanceTemplate_enableDisplay(t *testing.T) { t.Parallel() @@ -3872,6 +3913,32 @@ resource "google_compute_instance_template" "foobar" { `, context) } +func testAccComputeInstanceTemplate_enableUefiNetworking(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_image" "my_image" { + family = "ubuntu-2004-lts" + project = "ubuntu-os-cloud" +} + +resource "google_compute_instance_template" "foobar" { + name = "%{instance_name}" + machine_type = "n2-standard-2" + + disk { + source_image = data.google_compute_image.my_image.self_link + } + + network_interface { + network = "default" + } + + advanced_machine_features { + enable_uefi_networking = "%{enable_uefi_networking}" + } +} +`, context) +} + {{ if ne $.TargetVersionName `ga` -}} func testAccComputeInstanceTemplate_enableDisplay(suffix string) string { return fmt.Sprintf(` diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl index 66ff780220b1..4b6ba068521b 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl @@ -1520,6 +1520,33 @@ func TestAccComputeInstance_performanceMonitoringUnit(t *testing.T) { }) } +func TestAccComputeInstance_enableUefiNetworking(t *testing.T) { + t.Parallel() + + var instance compute.Instance + context_1 := map[string]interface{}{ + "instance_name": fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)), + "enable_uefi_networking": "true", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_enableUefiNetworking(context_1), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + resource.TestCheckResourceAttr("google_compute_instance.foobar", "advanced_machine_features.0.enable_uefi_networking", "true"), + ), + }, + computeInstanceImportStep("us-central1-a", context_1["instance_name"].(string), []string{}), + }, + }) +} + func TestAccComputeInstance_soleTenantNodeAffinities(t *testing.T) { t.Parallel() @@ -3508,6 +3535,43 @@ func TestAccComputeInstance_metadataStartupScript_update(t *testing.T) { }) } +func TestAccComputeInstance_metadataStartupScript_gracefulSwitch(t *testing.T) { + t.Parallel() + + var instance compute.Instance + var instanceName = fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_metadataStartupScript(instanceName, "e2-medium", "abc"), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceMetadata( + &instance, "foo", "abc"), + testAccCheckComputeInstanceMetadata( + &instance, "startup-script", "echo hi > /test.txt"), + ), + }, + { + Config: testAccComputeInstance_metadataStartupScript_gracefulSwitch(instanceName, "e2-medium", "abc"), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceMetadata( + &instance, "foo", "abc"), + testAccCheckComputeInstanceMetadata( + &instance, "startup-script", "echo hi > /test.txt"), + ), + }, + }, + }) +} + func TestAccComputeInstance_regionBootDisk(t *testing.T) { t.Parallel() @@ -3637,6 +3701,49 @@ func TestAccComputeInstance_proactiveAttributionLabel(t *testing.T) { }) } +func TestAccComputeInstance_autoDeleteUpdate(t *testing.T) { + t.Parallel() + + var instance compute.Instance + context_1 := map[string]interface{}{ + "instance_name": fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)), + "auto_delete": "true", + } + context_2 := map[string]interface{}{ + "instance_name": context_1["instance_name"], + "auto_delete": "false", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_autoDeleteUpdate(context_1), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance), + resource.TestCheckResourceAttr("google_compute_instance.foobar", "boot_disk.0.auto_delete", "true"), + ), + }, + { + Config: testAccComputeInstance_autoDeleteUpdate(context_2), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance), + resource.TestCheckResourceAttr("google_compute_instance.foobar", "boot_disk.0.auto_delete", "false"), + ), + }, + { + Config: testAccComputeInstance_autoDeleteUpdate(context_1), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance), + resource.TestCheckResourceAttr("google_compute_instance.foobar", "boot_disk.0.auto_delete", "true"), + ), + }, + }, + }) +} + func TestAccComputeInstance_keyRevocationActionType(t *testing.T) { t.Parallel() @@ -7260,6 +7367,35 @@ resource "google_compute_instance" "foobar" { `, context) } +func testAccComputeInstance_enableUefiNetworking(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_image" "my_image" { + family = "debian-12" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%{instance_name}" + machine_type = "n2-standard-2" + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + advanced_machine_features { + enable_uefi_networking = "%{enable_uefi_networking}" + } +} +`, context) +} + func testAccComputeInstance_advancedMachineFeaturesUpdated(instance string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { @@ -9877,6 +10013,39 @@ resource "google_compute_instance" "foobar" { `, instance, machineType, metadata) } +func testAccComputeInstance_metadataStartupScript_gracefulSwitch(instance, machineType, metadata 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 = "%s" + zone = "us-central1-a" + can_ip_forward = false + tags = ["foo", "bar"] + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + metadata = { + foo = "%s" + startup-script = "echo hi > /test.txt" + } + + allow_stopping_for_update = true +} +`, instance, machineType, metadata) +} func testAccComputeInstance_regionBootDisk(instance, diskName, suffix string) string { return fmt.Sprintf(` @@ -10933,6 +11102,28 @@ func TestAccComputeInstance_bootDisk_storagePoolSpecified(t *testing.T) { }) } +func TestAccComputeInstance_bootDisk_storagePoolSpecified_nameOnly(t *testing.T) { + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-instance-%s", acctest.RandString(t, 10)) + acctest.BootstrapComputeStoragePool(t, "basic-2", "hyperdisk-balanced") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_bootDisk_storagePoolSpecified(instanceName, "tf-bootstrap-storage-pool-hyperdisk-balanced-basic-2", envvar.GetTestZoneFromEnv()), + }, + { + ResourceName: "google_compute_instance.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeInstance_bootDisk_storagePoolSpecified(instanceName, storagePoolUrl, zone string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { @@ -11039,29 +11230,55 @@ resource "google_compute_instance" "foobar" { `, diskName, instanceName, machineType, zone, bootDiskInterface, allowStoppingForUpdate) } +func testAccComputeInstance_autoDeleteUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%{instance_name}" + machine_type = "n1-standard-1" + zone = "us-central1-a" + + boot_disk { + auto_delete = %{auto_delete} + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } +} +`, context) +} + func testAccComputeInstance_keyRevocationActionType(context map[string]interface{}) string { return acctest.Nprintf(` data "google_compute_image" "my_image" { - family = "debian-11" - project = "debian-cloud" + family = "debian-11" + project = "debian-cloud" } resource "google_compute_instance" "foobar" { - name = "%{instance_name}" - machine_type = "e2-medium" - zone = "us-central1-a" + name = "%{instance_name}" + machine_type = "e2-medium" + zone = "us-central1-a" - boot_disk { + boot_disk { initialize_params { - image = data.google_compute_image.my_image.self_link + image = data.google_compute_image.my_image.self_link + } } - } - network_interface { - network = "default" - } + network_interface { + network = "default" + } - key_revocation_action_type = %{key_revocation_action_type} + key_revocation_action_type = %{key_revocation_action_type} } `, context) } diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_network_peering_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_network_peering_meta.yaml.tmpl new file mode 100644 index 000000000000..dca2d8500dce --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_network_peering_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_network_peering' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Network' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_network_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_network_test.go.tmpl index 87dd65016fc7..079c80455819 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_network_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_network_test.go.tmpl @@ -224,7 +224,7 @@ func TestAccComputeNetwork_networkProfile(t *testing.T) { var network compute.Network suffixName := acctest.RandString(t, 10) - networkName := fmt.Sprintf("tf-network-profile-%s", suffixName) + networkName := fmt.Sprintf("tf-test-network-profile-%s", suffixName) projectId := envvar.GetTestProjectFromEnv() profileURL := fmt.Sprintf("https://www.googleapis.com/compute/beta/projects/%s/global/networkProfiles/europe-west1-b-vpc-roce", projectId) @@ -262,7 +262,7 @@ func TestAccComputeNetwork_numericId(t *testing.T) { { Config: testAccComputeNetwork_basic(networkName), Check: resource.ComposeTestCheckFunc( - resource.TestMatchResourceAttr("google_compute_network.bar", "numeric_id",regexp.MustCompile("^\\d{1,}$")), + resource.TestMatchResourceAttr("google_compute_network.bar", "numeric_id",regexp.MustCompile("^\\d{16,48}$")), resource.TestCheckResourceAttr("google_compute_network.bar", "id", networkId), ), }, @@ -335,7 +335,7 @@ func TestAccComputeNetwork_default_bgp_always_compare_med(t *testing.T) { var network compute.Network suffixName := acctest.RandString(t, 10) - networkName := fmt.Sprintf("tf-test-bgp-always-comapre-med-default-routes-%s", suffixName) + networkName := fmt.Sprintf("tf-test-bgp-always-compare-med-default-routes-%s", suffixName) expectedBgpAlwaysCompareMed := false @@ -768,7 +768,7 @@ resource "google_compute_network" "acc_network_bgp_best_path_selection_mode" { `, networkName, bgpBestPathSelection) } -func testAccComputeNetwork_bgp_always_compare_med(networkName string, bgpAlwaysComapreMed bool) string { +func testAccComputeNetwork_bgp_always_compare_med(networkName string, bgpAlwaysCompareMed bool) string { return fmt.Sprintf(` resource "google_compute_network" "acc_network_bgp_always_compare_med" { provider = google-beta @@ -777,7 +777,7 @@ resource "google_compute_network" "acc_network_bgp_always_compare_med" { bgp_best_path_selection_mode = "STANDARD" bgp_always_compare_med = %t } -`, networkName, bgpAlwaysComapreMed) +`, networkName, bgpAlwaysCompareMed) } func testAccComputeNetwork_bgp_inter_region_cost(networkName, bgpInterRegionCost string) string { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_default_network_tier_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_project_default_network_tier_meta.yaml.tmpl new file mode 100644 index 000000000000..a124585f80c9 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_default_network_tier_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_project_default_network_tier' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_meta.yaml.tmpl new file mode 100644 index 000000000000..40102da22a06 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_item_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_project_metadata_item' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_meta.yaml.tmpl new file mode 100644 index 000000000000..0687901d10e5 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_project_metadata_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_project_metadata' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_meta.yaml.tmpl new file mode 100644 index 000000000000..adc27b750221 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_region_instance_group_manager' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'InstanceGroupManager' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl index 273708aafe84..41f7638e5dc0 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl @@ -524,7 +524,7 @@ Google Cloud KMS.`, Optional: true, Computed: true, ForceNew: true, - ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6","IPV6_ONLY", ""}, false), + ValidateFunc: validation.StringInSlice([]string{"IPV4_ONLY", "IPV4_IPV6", ""}, false), Description: `The stack type for this network interface to identify whether the IPv6 feature is enabled or not. If not specified, IPV4_ONLY will be used.`, }, @@ -538,7 +538,6 @@ Google Cloud KMS.`, "ipv6_access_config": { Type: schema.TypeList, Optional: true, - Computed: true, ForceNew: true, Description: `An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig specified, then this instance will have no external IPv6 Internet access.`, Elem: &schema.Resource{ @@ -941,6 +940,12 @@ be from 0 to 999,999,999 inclusive.`, ValidateFunc: validation.StringInSlice([]string{"STANDARD", "ENHANCED", "ARCHITECTURAL"}, false), Description: `The PMU is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are "STANDARD", "ENHANCED", and "ARCHITECTURAL".`, }, + "enable_uefi_networking": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: `Whether to enable UEFI networking or not.`, + }, }, }, }, diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_meta.yaml.tmpl new file mode 100644 index 000000000000..8449a311f57f --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_region_instance_template' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'InstanceTemplate' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl index ff9454170bab..566dc4b5d263 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl @@ -835,6 +835,47 @@ func TestAccComputeRegionInstanceTemplate_performanceMonitoringUnit(t *testing.T }) } +func TestAccComputeRegionInstanceTemplate_enableUefiNetworking(t *testing.T) { + t.Parallel() + + var instanceTemplate compute.InstanceTemplate + context_1 := map[string]interface{}{ + "instance_name": fmt.Sprintf("tf-test-instance-template-%s", acctest.RandString(t, 10)), + "enable_uefi_networking": "false", + } + context_2 := map[string]interface{}{ + "instance_name": context_1["instance_name"].(string), + "enable_uefi_networking": "true", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionInstanceTemplate_enableUefiNetworking(context_1), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionInstanceTemplateExists(t, "google_compute_region_instance_template.foobar", &instanceTemplate), + resource.TestCheckResourceAttr("google_compute_region_instance_template.foobar", "advanced_machine_features.0.enable_uefi_networking", "false"), + ), + }, + { + Config: testAccComputeRegionInstanceTemplate_enableUefiNetworking(context_2), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionInstanceTemplateExists(t, "google_compute_region_instance_template.foobar", &instanceTemplate), + resource.TestCheckResourceAttr("google_compute_region_instance_template.foobar", "advanced_machine_features.0.enable_uefi_networking", "true"), + ), + }, + { + ResourceName: "google_compute_region_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + {{ if ne $.TargetVersionName `ga` -}} func TestAccComputeRegionInstanceTemplate_enableDisplay(t *testing.T) { @@ -3260,6 +3301,34 @@ resource "google_compute_region_instance_template" "foobar" { `, context) } +func testAccComputeRegionInstanceTemplate_enableUefiNetworking(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_image" "my_image" { + family = "ubuntu-2004-lts" + project = "ubuntu-os-cloud" +} + +resource "google_compute_region_instance_template" "foobar" { + name = "%{instance_name}" + region = "us-central1" + machine_type = "n2-standard-2" + + disk { + source_image = data.google_compute_image.my_image.self_link + } + + network_interface { + network = "default" + } + + advanced_machine_features { + enable_uefi_networking = "%{enable_uefi_networking}" + } +} +`, context) +} + + {{ if ne $.TargetVersionName `ga` -}} func testAccComputeRegionInstanceTemplate_enableDisplay(suffix string) string { return fmt.Sprintf(` diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_resource_policy_test.go b/mmv1/third_party/terraform/services/compute/resource_compute_resource_policy_test.go index f7eddb5603e4..051a3bda36d8 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_resource_policy_test.go +++ b/mmv1/third_party/terraform/services/compute/resource_compute_resource_policy_test.go @@ -69,6 +69,56 @@ func TestAccComputeResourcePolicy_attached(t *testing.T) { }) } +func TestAccComputeResourcePolicy_guestFlushEmptyValue(t *testing.T) { + t.Parallel() + + context_1 := map[string]interface{}{ + "suffix": fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)), + "snapshot_properties": ``, + } + + context_2 := map[string]interface{}{ + "suffix": context_1["suffix"], + "snapshot_properties": ` + snapshot_properties { + labels = { + foo = "bar" + } + } + `, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeResourcePolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeResourcePolicy_guestFlushEmptyValue(context_1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr("google_compute_resource_policy.foo", "guest_flush"), + ), + }, + { + ResourceName: "google_compute_resource_policy.foo", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeResourcePolicy_guestFlushEmptyValue(context_2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr("google_compute_resource_policy.foo", "guest_flush"), + ), + }, + { + ResourceName: "google_compute_resource_policy.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccComputeResourcePolicy_attached(suffix string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { @@ -119,3 +169,21 @@ resource "google_compute_resource_policy" "foo" { `, suffix, suffix) } + +func testAccComputeResourcePolicy_guestFlushEmptyValue(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_resource_policy" "foo" { + name = "tf-test-gce-policy%{suffix}" + region = "us-central1" + snapshot_schedule_policy { + schedule { + daily_schedule { + days_in_cycle = 1 + start_time = "04:00" + } + } + %{snapshot_properties} + } +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_router_interface_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_router_interface_meta.yaml.tmpl new file mode 100644 index 000000000000..4f93e86714e8 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_router_interface_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_router_interface' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Router' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_router_peer_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_router_peer_meta.yaml.tmpl new file mode 100644 index 000000000000..75f9ce2aa769 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_router_peer_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_router_peer' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Router' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.tmpl index df7961e3eebc..cbbe297d3c83 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.tmpl @@ -24,6 +24,26 @@ import ( {{- end }} ) +func verifyRulePriorityCompareEmptyValues(d *schema.ResourceData, rulePriority int, schemaKey string) bool { + if schemaRules, ok := d.GetOk("rule"); ok { + for _, itemRaw := range schemaRules.(*schema.Set).List() { + if itemRaw == nil { + continue + } + item := itemRaw.(map[string]interface{}) + + schemaPriority := item["priority"].(int) + if rulePriority == schemaPriority { + if tpgresource.IsEmptyValue(reflect.ValueOf(item[schemaKey])) { + return true + } + break + } + } + } + return false +} + // IsEmptyValue does not consider a empty PreconfiguredWafConfig object as empty so we check it's nested values func preconfiguredWafConfigIsEmptyValue(config *compute.SecurityPolicyRulePreconfiguredWafConfig) bool { if (tpgresource.IsEmptyValue(reflect.ValueOf(config.Exclusions)) && @@ -327,7 +347,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource { Description: `Rate limit key name applicable only for the following key types: HTTP_HEADER -- Name of the HTTP header whose value is taken as the key value. HTTP_COOKIE -- Name of the HTTP cookie whose value is taken as the key value.`, }, - {{ if ne $.TargetVersionName `ga` -}} "enforce_on_key_configs": { Type: schema.TypeList, Description: `Enforce On Key Config of this security policy`, @@ -348,7 +367,6 @@ func ResourceComputeSecurityPolicy() *schema.Resource { }, }, }, - {{- end }} "ban_threshold": { Type: schema.TypeList, @@ -547,6 +565,80 @@ func ResourceComputeSecurityPolicy() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"STANDARD", "PREMIUM"}, false), Description: `Rule visibility. Supported values include: "STANDARD", "PREMIUM".`, }, + "threshold_configs": { + Type: schema.TypeList, + Description: `Configuration options for layer7 adaptive protection for various customizable thresholds.`, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + Description: `The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the security policy.`, + ValidateFunc: validation.StringLenBetween(1, 63), + }, + "auto_deploy_load_threshold": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatAtLeast(0.0), + }, + "auto_deploy_confidence_threshold": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatBetween(0.0, 1.0), + }, + "auto_deploy_impacted_baseline_threshold": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatBetween(0.0, 1.0), + }, + "auto_deploy_expiration_sec": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(1, 7776000), + }, + "detection_load_threshold": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatAtLeast(0.0), + }, + "detection_absolute_qps": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatAtLeast(0.0), + }, + "detection_relative_to_baseline_qps": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: validation.FloatAtLeast(1.0), + }, + "traffic_granularity_configs": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + Description: `Type of this configuration.`, + ValidateFunc: validation.StringInSlice([]string{"HTTP_HEADER_HOST", "HTTP_PATH"}, false), + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: `Requests that match this value constitute a granular traffic unit.`, + }, + "enable_each_unique_value": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled, traffic matching each unique value for the specified type constitutes a separate traffic unit. It can only be set to true if value is empty.`, + }, + }, + }, + }, + }, + }, + }, }, }, }, @@ -833,72 +925,6 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ } } - {{ if eq $.TargetVersionName `ga` }} - 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{} - for _, rule := range oSet.List() { - oPriorities[int64(rule.(map[string]interface{})["priority"].(int))] = true - } - - for _, rule := range nSet.List() { - 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) { - 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).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) - - // 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) @@ -999,7 +1025,6 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ } } } - {{- end }} return resourceComputeSecurityPolicyRead(d, meta) } @@ -1188,7 +1213,7 @@ func flattenSecurityPolicyRules(rules []*compute.SecurityPolicyRule, d *schema.R "priority": rule.Priority, "action": rule.Action, "preview": rule.Preview, - "match": flattenMatch(rule.Match), + "match": flattenMatch(rule.Match, d, int(rule.Priority)), "preconfigured_waf_config": flattenPreconfiguredWafConfig(rule.PreconfiguredWafConfig, d, int(rule.Priority)), "rate_limit_options": flattenSecurityPolicyRuleRateLimitOptions(rule.RateLimitOptions), "redirect_options": flattenSecurityPolicyRedirectOptions(rule.RedirectOptions), @@ -1199,7 +1224,7 @@ func flattenSecurityPolicyRules(rules []*compute.SecurityPolicyRule, d *schema.R return rulesSchema } -func flattenMatch(match *compute.SecurityPolicyRuleMatcher) []map[string]interface{} { +func flattenMatch(match *compute.SecurityPolicyRuleMatcher, d *schema.ResourceData, rulePriority int) []map[string]interface{} { if match == nil { return nil } @@ -1208,7 +1233,7 @@ func flattenMatch(match *compute.SecurityPolicyRuleMatcher) []map[string]interfa "versioned_expr": match.VersionedExpr, "config": flattenMatchConfig(match.Config), "expr": flattenMatchExpr(match), - "expr_options": flattenMatchExprOptions(match.ExprOptions), + "expr_options": flattenMatchExprOptions(match.ExprOptions, d, rulePriority), } return []map[string]interface{}{data} @@ -1226,11 +1251,18 @@ func flattenMatchConfig(conf *compute.SecurityPolicyRuleMatcherConfig) []map[str return []map[string]interface{}{data} } -func flattenMatchExprOptions(exprOptions *compute.SecurityPolicyRuleMatcherExprOptions) []map[string]interface{} { +func flattenMatchExprOptions(exprOptions *compute.SecurityPolicyRuleMatcherExprOptions, d *schema.ResourceData, rulePriority int) []map[string]interface{} { if exprOptions == nil { return nil } + // We check if the API is returning a empty non-null value then we find the current value for this field in the rule config and check if its empty + if (tpgresource.IsEmptyValue(reflect.ValueOf(exprOptions.RecaptchaOptions.ActionTokenSiteKeys)) && + tpgresource.IsEmptyValue(reflect.ValueOf(exprOptions.RecaptchaOptions.SessionTokenSiteKeys))) && + verifyRulePriorityCompareEmptyValues(d, rulePriority, "recaptcha_options") { + return nil + } + data := map[string]interface{}{ "recaptcha_options": flattenMatchExprOptionsRecaptchaOptions(exprOptions.RecaptchaOptions), } @@ -1272,22 +1304,9 @@ func flattenPreconfiguredWafConfig(config *compute.SecurityPolicyRulePreconfigur return nil } - // We find the current value for this field in the config and check if its empty, then check if the API is returning a empty non-null value - if schemaRules, ok := d.GetOk("rule"); ok { - for _, itemRaw := range schemaRules.(*schema.Set).List() { - if itemRaw == nil { - continue - } - item := itemRaw.(map[string]interface{}) - - schemaPriority := item["priority"].(int) - if rulePriority == schemaPriority { - if preconfiguredWafConfigIsEmptyValue(config) && tpgresource.IsEmptyValue(reflect.ValueOf(item["preconfigured_waf_config"])) { - return nil - } - break - } - } + // We check if the API is returning a empty non-null value then we find the current value for this field in the rule config and check if its empty + if preconfiguredWafConfigIsEmptyValue(config) && verifyRulePriorityCompareEmptyValues(d, rulePriority, "preconfigured_waf_config") { + return nil } data := map[string]interface{}{ @@ -1403,10 +1422,47 @@ func expandLayer7DdosDefenseConfig(configured []interface{}) *compute.SecurityPo return &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfig{ Enable: data["enable"].(bool), RuleVisibility: data["rule_visibility"].(string), + ThresholdConfigs: expandThresholdConfigs(data["threshold_configs"].([]interface{})), ForceSendFields: []string{"Enable"}, } } +func expandThresholdConfigs(configured []interface{}) []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig{ + params := make([]*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig, 0, len(configured)) + for _, raw := range configured { + params = append(params, expandThresholdConfig(raw)) + } + return params +} + +func expandThresholdConfig(configured interface{}) *compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig{ + data := configured.(map[string]interface{}) + return &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig{ + AutoDeployConfidenceThreshold: data["auto_deploy_confidence_threshold"].(float64), + AutoDeployExpirationSec: int64(data["auto_deploy_expiration_sec"].(int)), + AutoDeployImpactedBaselineThreshold: data["auto_deploy_impacted_baseline_threshold"].(float64), + AutoDeployLoadThreshold: data["auto_deploy_load_threshold"].(float64), + DetectionAbsoluteQps: data["detection_absolute_qps"].(float64), + DetectionLoadThreshold: data["detection_load_threshold"].(float64), + DetectionRelativeToBaselineQps: data["detection_relative_to_baseline_qps"].(float64), + Name: data["name"].(string), + TrafficGranularityConfigs: expandTrafficGranularityConfig(data["traffic_granularity_configs"].([]interface{})), + } +} + +func expandTrafficGranularityConfig(configured []interface{}) []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig{ + params := make([]*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig, 0, len(configured)) + for _, raw := range configured { + data := raw.(map[string]interface{}) + params = append(params, &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig{ + EnableEachUniqueValue: data["enable_each_unique_value"].(bool), + Type: data["type"].(string), + Value: data["value"].(string), + }) + } + return params +} + {{ if ne $.TargetVersionName `ga` -}} func expandAutoDeployConfig(configured []interface{}) *compute.SecurityPolicyAdaptiveProtectionConfigAutoDeployConfig { if len(configured) == 0 || configured[0] == nil { @@ -1446,11 +1502,44 @@ func flattenLayer7DdosDefenseConfig(conf *compute.SecurityPolicyAdaptiveProtecti data := map[string]interface{}{ "enable": conf.Enable, "rule_visibility": conf.RuleVisibility, + "threshold_configs": flattenThresholdConfigs(conf.ThresholdConfigs), } return []map[string]interface{}{data} } +func flattenThresholdConfigs(conf []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig)[]map[string]interface{} { + configs := make([]map[string]interface{}, 0, len(conf)) + for _, field := range conf { + data := map[string]interface{}{ + "name": field.Name, + "auto_deploy_load_threshold": field.AutoDeployLoadThreshold, + "auto_deploy_confidence_threshold": field.AutoDeployConfidenceThreshold, + "auto_deploy_impacted_baseline_threshold": field.AutoDeployImpactedBaselineThreshold, + "auto_deploy_expiration_sec": field.AutoDeployExpirationSec, + "detection_load_threshold": field.DetectionLoadThreshold, + "detection_absolute_qps": field.DetectionAbsoluteQps, + "detection_relative_to_baseline_qps": field.DetectionRelativeToBaselineQps, + "traffic_granularity_configs": flattenTrafficGranularityConfigs(field.TrafficGranularityConfigs), + } + configs = append(configs, data) + } + return configs +} + +func flattenTrafficGranularityConfigs(conf []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig)[]map[string]interface{} { + configs := make([]map[string]interface{}, 0, len(conf)) + for _, field := range conf { + data := map[string]interface{}{ + "type": field.Type, + "value": field.Value, + "enable_each_unique_value": field.EnableEachUniqueValue, + } + configs = append(configs, data) + } + return configs +} + {{ if ne $.TargetVersionName `ga` -}} func flattenAutoDeployConfig(conf *compute.SecurityPolicyAdaptiveProtectionConfigAutoDeployConfig) []map[string]interface{} { if conf == nil { @@ -1481,9 +1570,7 @@ func expandSecurityPolicyRuleRateLimitOptions(configured []interface{}) *compute ConformAction: data["conform_action"].(string), EnforceOnKey: data["enforce_on_key"].(string), EnforceOnKeyName: data["enforce_on_key_name"].(string), - {{- if ne $.TargetVersionName "ga" }} EnforceOnKeyConfigs: expandSecurityPolicyEnforceOnKeyConfigs(data["enforce_on_key_configs"].([]interface{})), - {{- end }} BanDurationSec: int64(data["ban_duration_sec"].(int)), ExceedRedirectOptions: expandSecurityPolicyRuleRedirectOptions(data["exceed_redirect_options"].([]interface{})), {{- if eq $.TargetVersionName "ga" }} @@ -1506,7 +1593,6 @@ func expandThreshold(configured []interface{}) *compute.SecurityPolicyRuleRateLi } } -{{ if ne $.TargetVersionName `ga` -}} func expandSecurityPolicyEnforceOnKeyConfigs(configured []interface{}) []*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig { params := make([]*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig, 0, len(configured)) @@ -1525,7 +1611,6 @@ func expandSecurityPolicyEnforceOnKeyConfigsFields(raw interface{}) *compute.Sec EnforceOnKeyName: data["enforce_on_key_name"].(string), } } -{{- end }} func flattenSecurityPolicyRuleRateLimitOptions(conf *compute.SecurityPolicyRuleRateLimitOptions) []map[string]interface{} { if conf == nil { @@ -1539,9 +1624,7 @@ func flattenSecurityPolicyRuleRateLimitOptions(conf *compute.SecurityPolicyRuleR "conform_action": conf.ConformAction, "enforce_on_key": conf.EnforceOnKey, "enforce_on_key_name": conf.EnforceOnKeyName, - {{- if ne $.TargetVersionName "ga" }} "enforce_on_key_configs": flattenSecurityPolicyEnforceOnKeyConfigs(conf.EnforceOnKeyConfigs), - {{- end }} "ban_duration_sec": conf.BanDurationSec, "exceed_redirect_options": flattenSecurityPolicyRedirectOptions(conf.ExceedRedirectOptions), } @@ -1574,7 +1657,6 @@ func expandSecurityPolicyRuleRedirectOptions(configured []interface{}) *compute. } } -{{ if ne $.TargetVersionName `ga` -}} func flattenSecurityPolicyEnforceOnKeyConfigs(conf []*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig) []map[string]interface{} { if conf == nil || len(conf) == 0 { return nil @@ -1597,7 +1679,6 @@ func flattenSecurityPolicyEnforceOnKeyConfigsFields(conf *compute.SecurityPolicy "enforce_on_key_type": conf.EnforceOnKeyType, } } -{{- end }} func flattenSecurityPolicyRedirectOptions(conf *compute.SecurityPolicyRuleRedirectOptions) []map[string]interface{} { if conf == nil { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_meta.yaml.tmpl new file mode 100644 index 000000000000..9aa75826ed25 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_security_policy' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'SecurityPolicy' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.tmpl index 27d2c3755737..1345b1d7f4fc 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.tmpl @@ -369,6 +369,36 @@ func TestAccComputeSecurityPolicy_withoutAdaptiveProtection(t *testing.T) { }) } +func TestAccComputeSecurityPolicy_withAdaptiveProtection_withThresholdConfigs(t *testing.T) { + t.Parallel() + + spName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeSecurityPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeSecurityPolicy_withAdaptiveProtection_enabled_withThresholdConfigs(spName), + }, + { + ResourceName: "google_compute_security_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeSecurityPolicy_withAdaptiveProtection_update_ThresholdConfigs(spName), + }, + { + ResourceName: "google_compute_security_policy.policy", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + {{ if ne $.TargetVersionName `ga` -}} func TestAccComputeSecurityPolicy_withAdaptiveProtectionAutoDeployConfig(t *testing.T) { t.Parallel() @@ -445,7 +475,6 @@ func TestAccComputeSecurityPolicy_withRateLimitWithRedirectOptions(t *testing.T) }) } -{{ if ne $.TargetVersionName `ga` -}} func TestAccComputeSecurityPolicy_withRateLimit_withEnforceOnKeyConfigs(t *testing.T) { t.Parallel() @@ -561,9 +590,6 @@ func TestAccComputeSecurityPolicy_EnforceOnKeyUpdates(t *testing.T) { }) } - -{{ end }} - func TestAccComputeSecurityPolicy_withRecaptchaOptionsConfig(t *testing.T) { t.Parallel() @@ -1363,7 +1389,7 @@ resource "google_compute_security_policy" "policy" { } log_level = "VERBOSE" user_ip_request_headers = [ - "True-Client-IP", + "True-Client-IP", "x-custom-ip" ] } @@ -1480,6 +1506,62 @@ resource "google_compute_security_policy" "policy" { `, spName) } +func testAccComputeSecurityPolicy_withAdaptiveProtection_enabled_withThresholdConfigs(spName string) string { + return fmt.Sprintf(` +resource "google_compute_security_policy" "policy" { + name = "%s" + description = "updated description" + + adaptive_protection_config { + layer_7_ddos_defense_config { + enable = true + rule_visibility = "STANDARD" + threshold_configs { + name = "threshold-name" + auto_deploy_load_threshold = 0.1 + auto_deploy_confidence_threshold = 0.5 + auto_deploy_impacted_baseline_threshold = 0.02 + auto_deploy_expiration_sec = 3600 + detection_load_threshold = 0.7 + detection_absolute_qps = 1.0 + detection_relative_to_baseline_qps = 1.1 + traffic_granularity_configs { + type = "HTTP_HEADER_HOST" + enable_each_unique_value = true + } + } + } + } +} +`, spName) +} + +func testAccComputeSecurityPolicy_withAdaptiveProtection_update_ThresholdConfigs(spName string) string { + return fmt.Sprintf(` +resource "google_compute_security_policy" "policy" { + name = "%s" + description = "updated description" + + adaptive_protection_config { + layer_7_ddos_defense_config { + enable = true + rule_visibility = "STANDARD" + threshold_configs { + name = "threshold-name-updated" + auto_deploy_load_threshold = 0.2 + auto_deploy_confidence_threshold = 0.6 + auto_deploy_impacted_baseline_threshold = 0.03 + auto_deploy_expiration_sec = 7200 + detection_load_threshold = 0.8 + detection_absolute_qps = 1.1 + detection_relative_to_baseline_qps = 1.2 + } + } + } +} +`, spName) +} + func testAccComputeSecurityPolicy_withAdaptiveProtection_update(spName string) string { return fmt.Sprintf(` resource "google_compute_security_policy" "policy" { @@ -1624,7 +1706,6 @@ resource "google_compute_security_policy" "policy" { `, spName) } -{{ if ne $.TargetVersionName `ga` -}} func testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKey(spName string) string { return fmt.Sprintf(` resource "google_compute_security_policy" "policy" { @@ -1854,7 +1935,6 @@ resource "google_compute_security_policy" "policy" { } `, spName) } -{{- end }} func TestAccComputeSecurityPolicy_withRedirectOptionsRecaptcha(t *testing.T) { t.Parallel() diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_host_project_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_host_project_meta.yaml.tmpl new file mode 100644 index 000000000000..d398b3b4bde1 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_host_project_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_shared_vpc_host_project' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_service_project_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_service_project_meta.yaml.tmpl new file mode 100644 index 000000000000..67589d7833cb --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_shared_vpc_service_project_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_shared_vpc_service_project' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_target_pool_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_target_pool_meta.yaml.tmpl new file mode 100644 index 000000000000..dabb9e79d2eb --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_compute_target_pool_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_compute_target_pool' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'TargetPool' diff --git a/mmv1/third_party/terraform/services/compute/resource_usage_export_bucket.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket.go.tmpl similarity index 100% rename from mmv1/third_party/terraform/services/compute/resource_usage_export_bucket.go.tmpl rename to mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket.go.tmpl diff --git a/mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket_meta.yaml.tmpl b/mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket_meta.yaml.tmpl new file mode 100644 index 000000000000..8fe2affd5861 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_project_usage_export_bucket' +generation_type: 'handwritten' +api_service_name: 'compute.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'beta' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/compute/resource_usage_export_bucket_test.go b/mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket_test.go similarity index 100% rename from mmv1/third_party/terraform/services/compute/resource_usage_export_bucket_test.go rename to mmv1/third_party/terraform/services/compute/resource_project_usage_export_bucket_test.go diff --git a/mmv1/third_party/terraform/services/container/node_config.go.tmpl b/mmv1/third_party/terraform/services/container/node_config.go.tmpl index 7bb8a65cb8c5..6b54e3a49c95 100644 --- a/mmv1/third_party/terraform/services/container/node_config.go.tmpl +++ b/mmv1/third_party/terraform/services/container/node_config.go.tmpl @@ -835,6 +835,29 @@ func schemaNodePoolAutoConfigNodeKubeletConfig() *schema.Schema { } } +// Separate since this currently only supports a single value -- a subset of +// the overall LinuxNodeConfig +func schemaNodePoolAutoConfigLinuxNodeConfig() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Description: `Linux node configuration options.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cgroup_mode": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{"CGROUP_MODE_UNSPECIFIED", "CGROUP_MODE_V1", "CGROUP_MODE_V2"}, false), + Description: `cgroupMode specifies the cgroup mode to be used on the node.`, + DiffSuppressFunc: tpgresource.EmptyOrDefaultStringSuppress("CGROUP_MODE_UNSPECIFIED"), + }, + }, + }, + } +} + func expandNodeConfigDefaults(configured interface{}) *container.NodeConfigDefaults { configs := configured.([]interface{}) if len(configs) == 0 || configs[0] == nil { @@ -1578,10 +1601,8 @@ func flattenResourceManagerTags(c *container.ResourceManagerTags) map[string]int rmt := make(map[string]interface{}) - if c != nil { - for k, v := range c.Tags { - rmt[k] = v - } + for k, v := range c.Tags { + rmt[k] = v } return rmt diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.tmpl b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.tmpl index a661ffbc58d1..f84cd571857c 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.tmpl +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.tmpl @@ -195,9 +195,7 @@ func ResourceContainerCluster() *schema.Resource { CustomizeDiff: customdiff.All( resourceNodeConfigEmptyGuestAccelerator, customdiff.ForceNewIfChange("enable_l4_ilb_subsetting", isBeenEnabled), -{{- if ne $.TargetVersionName "ga" }} customdiff.ForceNewIfChange("enable_fqdn_network_policy", isBeenEnabled), -{{- end }} containerClusterAutopilotCustomizeDiff, containerClusterNodeVersionRemoveDefaultCustomizeDiff, containerClusterNetworkPolicyEmptyCustomizeDiff, @@ -1506,6 +1504,7 @@ func ResourceContainerCluster() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "node_kubelet_config": schemaNodePoolAutoConfigNodeKubeletConfig(), + "linux_node_config": schemaNodePoolAutoConfigLinuxNodeConfig(), "network_tags": { Type: schema.TypeList, Optional: true, @@ -2090,14 +2089,12 @@ func ResourceContainerCluster() *schema.Resource { Description: `Whether multi-networking is enabled for this cluster.`, Default: false, }, -{{- if ne $.TargetVersionName "ga" }} "enable_fqdn_network_policy": { Type: schema.TypeBool, Optional: true, Description: `Whether FQDN Network Policy is enabled on this cluster.`, Default: false, }, -{{- end }} "private_ipv6_google_access": { Type: schema.TypeString, Optional: true, @@ -2322,6 +2319,30 @@ func ResourceContainerCluster() *schema.Resource { }, }, {{- end }} + "enterprise_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Computed: true, + Description: `Defines the config needed to enable/disable GKE Enterprise`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_tier": { + Type: schema.TypeString, + Computed: true, + Description: `Indicates the effective cluster tier. Available options include STANDARD and ENTERPRISE.`, + }, + "desired_tier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{"STANDARD", "ENTERPRISE"}, false), + Description: `Indicates the desired cluster tier. Available options include STANDARD and ENTERPRISE.`, + DiffSuppressFunc: tpgresource.EmptyOrDefaultStringSuppress("CLUSTER_TIER_UNSPECIFIED"), + }, + }, + }, + }, }, } } @@ -2484,9 +2505,7 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er GatewayApiConfig: expandGatewayApiConfig(d.Get("gateway_api_config")), EnableMultiNetworking: d.Get("enable_multi_networking").(bool), DefaultEnablePrivateNodes: expandDefaultEnablePrivateNodes(d), -{{- if ne $.TargetVersionName "ga" }} EnableFqdnNetworkPolicy: d.Get("enable_fqdn_network_policy").(bool), -{{- end }} }, MasterAuth: expandMasterAuth(d.Get("master_auth")), NotificationConfig: expandNotificationConfig(d.Get("notification_config")), @@ -2644,6 +2663,10 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er cluster.SecurityPostureConfig = expandSecurityPostureConfig(v) } + if v, ok := d.GetOk("enterprise_config"); ok { + cluster.EnterpriseConfig = expandEnterpriseConfig(v) + } + needUpdateAfterCreate := false // For now PSC based cluster don't support `enable_private_endpoint` on `create`, but only on `update` API call. @@ -2827,6 +2850,34 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er } } + if linuxNodeConfig, ok := d.GetOk("node_pool_auto_config.0.linux_node_config"); ok { + name := containerClusterFullName(project, location, clusterName) + req := &container.UpdateClusterRequest{ + Update: &container.ClusterUpdate{ + DesiredNodePoolAutoConfigLinuxNodeConfig: expandLinuxNodeConfig(linuxNodeConfig), + }, + } + + err = transport_tpg.Retry(transport_tpg.RetryOptions{ + RetryFunc: func() error { + clusterUpdateCall := config.NewContainerClient(userAgent).Projects.Locations.Clusters.Update(name, req) + if config.UserProjectOverride { + clusterUpdateCall.Header().Add("X-Goog-User-Project", project) + } + op, err = clusterUpdateCall.Do() + return err + }, + }) + if err != nil { + return errwrap.Wrapf("Error updating LinuxNodeConfig: {{"{{"}}err{{"}}"}}", err) + } + + err = ContainerOperationWait(config, op, project, location, "updating LinuxNodeConfig", userAgent, d.Timeout(schema.TimeoutCreate)) + if err != nil { + return errwrap.Wrapf("Error while waiting to update LinuxNodeConfig: {{"{{"}}err{{"}}"}}", err) + } + } + if err := resourceContainerClusterRead(d, meta); err != nil { return err } @@ -3029,11 +3080,9 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("enable_multi_networking", cluster.NetworkConfig.EnableMultiNetworking); err != nil { return fmt.Errorf("Error setting enable_multi_networking: %s", err) } -{{- if ne $.TargetVersionName "ga" }} if err := d.Set("enable_fqdn_network_policy", cluster.NetworkConfig.EnableFqdnNetworkPolicy); err != nil { return fmt.Errorf("Error setting enable_fqdn_network_policy: %s", err) } -{{- end }} if err := d.Set("private_ipv6_google_access", cluster.NetworkConfig.PrivateIpv6GoogleAccess); err != nil { return fmt.Errorf("Error setting private_ipv6_google_access: %s", err) } @@ -3179,6 +3228,10 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro } {{- end }} + if err := d.Set("enterprise_config", flattenEnterpriseConfig(cluster.EnterpriseConfig)); err != nil { + return err + } + return nil } @@ -3504,7 +3557,6 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er log.Printf("[INFO] GKE cluster %s L4 ILB Subsetting has been updated to %v", d.Id(), enabled) } -{{ if ne $.TargetVersionName `ga` -}} if d.HasChange("enable_fqdn_network_policy") { enabled := d.Get("enable_fqdn_network_policy").(bool) req := &container.UpdateClusterRequest{ @@ -3520,7 +3572,6 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er log.Printf("[INFO] GKE cluster %s FQDN Network Policy has been updated to %v", d.Id(), enabled) } -{{- end }} if d.HasChange("enable_cilium_clusterwide_network_policy") { enabled := d.Get("enable_cilium_clusterwide_network_policy").(bool) @@ -4485,6 +4536,41 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er log.Printf("[INFO] GKE cluster %s node pool auto config resource manager tags have been updated", d.Id()) } + if d.HasChange("node_pool_auto_config.0.linux_node_config") { + req := &container.UpdateClusterRequest{ + Update: &container.ClusterUpdate{ + DesiredNodePoolAutoConfigLinuxNodeConfig: expandLinuxNodeConfig( + d.Get("node_pool_auto_config.0.linux_node_config"), + ), + }, + } + + updateF := updateFunc(req, "updating GKE cluster node pool auto config linux node config") + // Call update serially. + if err := transport_tpg.LockedCall(lockKey, updateF); err != nil { + return err + } + + log.Printf("[INFO] GKE cluster %s node pool auto config linux_node_config parameters have been updated", d.Id()) + } + + if d.HasChange("enterprise_config") && d.HasChange("enterprise_config.0.desired_tier") { + req := &container.UpdateClusterRequest{ + Update: &container.ClusterUpdate{ + DesiredEnterpriseConfig: &container.DesiredEnterpriseConfig{ + DesiredTier: d.Get("enterprise_config.0.desired_tier").(string), + }, + }, + } + updateF := updateFunc(req, "updating GKE cluster Enterprise Config") + // Call update serially. + if err := transport_tpg.LockedCall(lockKey, updateF); err != nil { + return err + } + + log.Printf("[INFO] GKE cluster %s Enterprise Config has been updated to %#v", d.Id(), req.Update.DesiredSecurityPostureConfig) + } + d.Partial(false) {{ if ne $.TargetVersionName `ga` -}} @@ -5220,6 +5306,36 @@ func flattenSecurityPostureConfig(spc *container.SecurityPostureConfig) []map[st return []map[string]interface{}{result} } +func expandEnterpriseConfig(configured interface{}) *container.EnterpriseConfig { + l := configured.([]interface{}) + if len(l) == 0 { + return nil + } + + ec := &container.EnterpriseConfig{} + enterpriseConfig := l[0].(map[string]interface{}) + if v, ok := enterpriseConfig["cluster_tier"]; ok { + ec.ClusterTier = v.(string) + } + + if v, ok := enterpriseConfig["desired_tier"]; ok { + ec.DesiredTier = v.(string) + } + return ec +} + +func flattenEnterpriseConfig(ec *container.EnterpriseConfig) []map[string]interface{} { + if ec == nil { + return nil + } + result := make(map[string]interface{}) + + result["cluster_tier"] = ec.ClusterTier + result["desired_tier"] = ec.DesiredTier + + return []map[string]interface{}{result} +} + func flattenAdditionalPodRangesConfig(ipAllocationPolicy *container.IPAllocationPolicy) []map[string]interface{} { if ipAllocationPolicy == nil { return nil @@ -6776,6 +6892,11 @@ func flattenNodePoolAutoConfig(c *container.NodePoolAutoConfig) []map[string]int if c.ResourceManagerTags != nil { result["resource_manager_tags"] = flattenResourceManagerTags(c.ResourceManagerTags) } + if c.LinuxNodeConfig != nil { + result["linux_node_config"] = []map[string]interface{}{ + {"cgroup_mode": c.LinuxNodeConfig.CgroupMode}, + } + } return []map[string]interface{}{result} } diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_meta.yaml.tmpl b/mmv1/third_party/terraform/services/container/resource_container_cluster_meta.yaml.tmpl new file mode 100644 index 000000000000..80b6faea32eb --- /dev/null +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_container_cluster' +generation_type: 'handwritten' +api_service_name: 'container.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'v1beta1' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'Cluster' diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.tmpl b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.tmpl index 31611588ee24..ef6ca08968ca 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.tmpl +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.tmpl @@ -508,7 +508,6 @@ func TestAccContainerCluster_withMultiNetworking(t *testing.T) { }) } -{{ if ne $.TargetVersionName `ga` -}} func TestAccContainerCluster_withFQDNNetworkPolicy(t *testing.T) { t.Parallel() @@ -540,7 +539,6 @@ func TestAccContainerCluster_withFQDNNetworkPolicy(t *testing.T) { }, }) } -{{- end }} func TestAccContainerCluster_withAdditiveVPC(t *testing.T) { t.Parallel() @@ -768,7 +766,6 @@ resource "google_container_cluster" "cluster" { `, clusterName) } -{{ if ne $.TargetVersionName `ga` -}} func testAccContainerCluster_withFQDNNetworkPolicy(clusterName string, enabled bool) string { return fmt.Sprintf(` data "google_container_engine_versions" "uscentral1a" { @@ -829,7 +826,6 @@ resource "google_container_cluster" "cluster" { } `, clusterName, clusterName, enabled) } -{{- end }} func TestAccContainerCluster_withNetworkPolicyEnabled(t *testing.T) { t.Parallel() @@ -11188,7 +11184,7 @@ func testAccContainerCluster_additional_pod_ranges_config(name string, nameCount master_ipv4_cidr_block = "172.16.0.0/28" } - # supresses permadiff + # suppresses permadiff dns_config { cluster_dns = "CLOUD_DNS" cluster_dns_domain = "cluster.local" @@ -12726,3 +12722,163 @@ resource "google_container_cluster" "primary" { } }`, name, enabled) } + +func TestAccContainerCluster_withCgroupMode(t *testing.T) { + t.Parallel() + + clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withCgroupMode(clusterName, "CGROUP_MODE_V2"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("google_container_cluster.primary", "node_pool_auto_config.0.linux_node_config.0.cgroup_mode"), + resource.TestCheckResourceAttr("google_container_cluster.primary", "node_pool_auto_config.0.linux_node_config.0.cgroup_mode", "CGROUP_MODE_V2"), + ), + }, + { + ResourceName: "google_container_cluster.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + }, + }) +} + +func TestAccContainerCluster_withCgroupModeUpdate(t *testing.T) { + t.Parallel() + + clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_autopilot_minimal(clusterName), + }, + { + ResourceName: "google_container_cluster.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + { + Config: testAccContainerCluster_withCgroupMode(clusterName, "CGROUP_MODE_V2"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("google_container_cluster.primary", "node_pool_auto_config.0.linux_node_config.0.cgroup_mode"), + resource.TestCheckResourceAttr("google_container_cluster.primary", "node_pool_auto_config.0.linux_node_config.0.cgroup_mode", "CGROUP_MODE_V2"), + ), + }, + { + ResourceName: "google_container_cluster.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + }, + }) +} + +func testAccContainerCluster_withCgroupMode(name string, cgroupMode string) string { + return fmt.Sprintf(` +resource "google_container_cluster" "primary" { + name = "%s" + enable_autopilot = true + deletion_protection = false + node_pool_auto_config { + linux_node_config { + cgroup_mode = "%s" + } + } +} + `, name, cgroupMode) +} + +func TestAccContainerCluster_withEnterpriseConfig(t *testing.T) { + t.Parallel() + + clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) + networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName) + pid := envvar.GetTestProjectFromEnv() + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_updateEnterpriseConfig(pid, clusterName, networkName, subnetworkName, "STANDARD"), + }, + { + ResourceName: "google_container_cluster.with_enterprise_config", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + { + Config: testAccContainerCluster_updateEnterpriseConfig(pid, clusterName, networkName, subnetworkName, "ENTERPRISE"), + }, + { + ResourceName: "google_container_cluster.with_enterprise_config", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + { + Config: testAccContainerCluster_removeEnterpriseConfig(pid, clusterName, networkName, subnetworkName), + }, + { + ResourceName: "google_container_cluster.with_enterprise_config", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + }, + }) +} + +func testAccContainerCluster_updateEnterpriseConfig(projectID, clusterName, networkName, subnetworkName string, desiredTier string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%s" +} + +resource "google_container_cluster" "with_enterprise_config" { + name = "%s" + location = "us-central1-a" + initial_node_count = 1 + enterprise_config { + desired_tier = "%s" + } + network = "%s" + subnetwork = "%s" + + deletion_protection = false +} +`, projectID, clusterName, desiredTier, networkName, subnetworkName) +} + +func testAccContainerCluster_removeEnterpriseConfig(projectID, clusterName, networkName, subnetworkName string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%s" +} + +resource "google_container_cluster" "with_enterprise_config" { + name = "%s" + location = "us-central1-a" + initial_node_count = 1 + network = "%s" + subnetwork = "%s" + + deletion_protection = false +} +`, projectID, clusterName, networkName, subnetworkName) +} + diff --git a/mmv1/third_party/terraform/services/container/resource_container_node_pool_meta.yaml.tmpl b/mmv1/third_party/terraform/services/container/resource_container_node_pool_meta.yaml.tmpl new file mode 100644 index 000000000000..75848a869743 --- /dev/null +++ b/mmv1/third_party/terraform/services/container/resource_container_node_pool_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_container_node_pool' +generation_type: 'handwritten' +api_service_name: 'container.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'v1beta1' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'NodePool' diff --git a/mmv1/third_party/terraform/services/containerazure/resource_container_azure_cluster_meta.yaml b/mmv1/third_party/terraform/services/containerazure/resource_container_azure_cluster_meta.yaml index 050efdd73bfb..b6203a779c8b 100644 --- a/mmv1/third_party/terraform/services/containerazure/resource_container_azure_cluster_meta.yaml +++ b/mmv1/third_party/terraform/services/containerazure/resource_container_azure_cluster_meta.yaml @@ -1,5 +1,5 @@ -resource: 'google_container_azure_node_pool' +resource: 'google_container_azure_cluster' generation_type: 'dcl' api_service_name: 'gkemulticloud.googleapis.com' api_version: 'v1' -api_resource_type_kind: 'AzureNodePool' +api_resource_type_kind: 'AzureCluster' diff --git a/mmv1/third_party/terraform/services/containerazure/resource_container_azure_node_pool_meta.yaml b/mmv1/third_party/terraform/services/containerazure/resource_container_azure_node_pool_meta.yaml index d56ecfa56e4b..050efdd73bfb 100644 --- a/mmv1/third_party/terraform/services/containerazure/resource_container_azure_node_pool_meta.yaml +++ b/mmv1/third_party/terraform/services/containerazure/resource_container_azure_node_pool_meta.yaml @@ -1,5 +1,5 @@ -resource: 'google_container_aws_node_pool' +resource: 'google_container_azure_node_pool' generation_type: 'dcl' api_service_name: 'gkemulticloud.googleapis.com' api_version: 'v1' -api_resource_type_kind: 'AwsNodePool' +api_resource_type_kind: 'AzureNodePool' diff --git a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_meta.yaml.tmpl b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_meta.yaml.tmpl new file mode 100644 index 000000000000..64b7b7494a29 --- /dev/null +++ b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_dataflow_flex_template_job' +generation_type: 'handwritten' +api_service_name: 'dataflow.googleapis.com' +api_version: 'v1b3' +api_resource_type_kind: 'Job' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_test.go.tmpl b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_test.go.tmpl index a8d095fe46f7..917f1b8a674d 100644 --- a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_test.go.tmpl +++ b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_flex_template_job_test.go.tmpl @@ -136,6 +136,9 @@ func TestAccDataflowFlexTemplateJob_FullUpdate(t *testing.T) { PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckDataflowJobDestroyProducer(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, Steps: []resource.TestStep{ { Config: testAccDataflowFlexTemplateJob_dataflowFlexTemplateJobFull(job, bucket, topic, randStr), @@ -870,7 +873,13 @@ resource "google_storage_bucket_object" "schema" { EOF } +resource "time_sleep" "wait_bind_iam_roles" { + depends_on = [google_project_iam_member.dataflow-worker, google_project_iam_member.dataflow-storage] + create_duration = "300s" +} + resource "google_dataflow_flex_template_job" "flex_job_fullupdate" { + depends_on = [time_sleep.wait_bind_iam_roles] name = "%s" container_spec_gcs_path = "gs://${data.google_storage_bucket_object.flex_template.bucket}/${data.google_storage_bucket_object.flex_template.name}" on_delete = "cancel" diff --git a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job_meta.yaml b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job_meta.yaml new file mode 100644 index 000000000000..d276c962797a --- /dev/null +++ b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_dataflow_job' +generation_type: 'handwritten' +api_service_name: 'dataflow.googleapis.com' +api_version: 'v1b3' +api_resource_type_kind: 'Job' diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster.go b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster.go index 288b722f0a35..9f53c12df146 100644 --- a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster.go +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster.go @@ -62,6 +62,7 @@ var ( "cluster_config.0.gce_cluster_config.0.metadata", "cluster_config.0.gce_cluster_config.0.reservation_affinity", "cluster_config.0.gce_cluster_config.0.node_group_affinity", + "cluster_config.0.gce_cluster_config.0.confidential_instance_config", } schieldedInstanceConfigKeys = []string{ @@ -76,6 +77,10 @@ var ( "cluster_config.0.gce_cluster_config.0.reservation_affinity.0.values", } + confidentialInstanceConfigKeys = []string{ + "cluster_config.0.gce_cluster_config.0.confidential_instance_config.0.enable_confidential_compute", + } + masterDiskConfigKeys = diskConfigKeys("master_config") workerDiskConfigKeys = diskConfigKeys("worker_config") preemptibleWorkerDiskConfigKeys = diskConfigKeys("preemptible_worker_config") @@ -757,6 +762,26 @@ func ResourceDataprocCluster() *schema.Resource { }, }, }, + "confidential_instance_config": { + Type: schema.TypeList, + Optional: true, + AtLeastOneOf: gceClusterConfigKeys, + Computed: true, + MaxItems: 1, + Description: `Confidential Instance Config for clusters using Compute Engine Confidential VMs.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_confidential_compute": { + Type: schema.TypeBool, + Optional: true, + Default: false, + AtLeastOneOf: confidentialInstanceConfigKeys, + ForceNew: true, + Description: `Defines whether the instance should have confidential compute enabled.`, + }, + }, + }, + }, }, }, }, @@ -2246,6 +2271,13 @@ func expandGceClusterConfig(d *schema.ResourceData, config *transport_tpg.Config conf.NodeGroupAffinity.NodeGroupUri = v.(string) } } + if v, ok := d.GetOk("cluster_config.0.gce_cluster_config.0.confidential_instance_config"); ok { + cfgCic := v.([]interface{})[0].(map[string]interface{}) + conf.ConfidentialInstanceConfig = &dataproc.ConfidentialInstanceConfig{} + if v, ok := cfgCic["enable_confidential_compute"]; ok { + conf.ConfidentialInstanceConfig.EnableConfidentialCompute = v.(bool) + } + } return conf, nil } @@ -3194,6 +3226,13 @@ func flattenGceClusterConfig(d *schema.ResourceData, gcc *dataproc.GceClusterCon }, } } + if gcc.ConfidentialInstanceConfig != nil { + gceConfig["confidential_instance_config"] = []map[string]interface{}{ + { + "enable_confidential_compute": gcc.ConfidentialInstanceConfig.EnableConfidentialCompute, + }, + } + } return []map[string]interface{}{gceConfig} } diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_meta.yaml b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_meta.yaml new file mode 100644 index 000000000000..853ef5c93b22 --- /dev/null +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_dataproc_cluster' +generation_type: 'handwritten' +api_service_name: 'dataproc.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Cluster' diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_test.go.tmpl b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_test.go.tmpl index 2fe9b046a8ba..8c8dd1a0f7b5 100644 --- a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_test.go.tmpl +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_cluster_test.go.tmpl @@ -105,14 +105,12 @@ func TestAccDataprocCluster_basic(t *testing.T) { } func TestAccDataprocVirtualCluster_basic(t *testing.T) { - // Currently failing - acctest.SkipIfVcr(t) t.Parallel() var cluster dataproc.Cluster rnd := acctest.RandString(t, 10) pid := envvar.GetTestProjectFromEnv() - version := "3.1-dataproc-7" + version := "3.5-dataproc-17" networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster") subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName) @@ -256,6 +254,51 @@ func TestAccDataprocCluster_withInternalIpOnlyTrueAndShieldedConfig(t *testing.T }) } +func TestAccDataprocCluster_withConfidentialCompute(t *testing.T) { + t.Parallel() + + var cluster dataproc.Cluster + rnd := acctest.RandString(t, 10) + networkName := acctest.BootstrapSharedTestNetwork(t, "dataproc-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "dataproc-cluster", networkName) + acctest.BootstrapFirewallForDataprocSharedNetwork(t, "dataproc-cluster", networkName) + imageUri := "https://www.googleapis.com/compute/v1/projects/cloud-dataproc/global/images/dataproc-2-1-ubu20-20241026-165100-rc01" + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckDataprocClusterDestroy(t), + Steps: []resource.TestStep{ + { + Config: testAccDataprocCluster_withConfidentialCompute(rnd, subnetworkName, imageUri), + Check: resource.ComposeTestCheckFunc( + testAccCheckDataprocClusterExists(t, "google_dataproc_cluster.confidential", &cluster), + + // Check confidential compute + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.gce_cluster_config.0.confidential_instance_config.0.enable_confidential_compute", "true"), + + // Check master + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.master_config.0.machine_type", "n2d-standard-2"), + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.master_config.0.image_uri", imageUri), + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.master_config.0.min_cpu_platform", "AMD Rome"), + + // Check worker + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.worker_config.0.machine_type", "n2d-standard-2"), + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.worker_config.0.image_uri", imageUri), + resource.TestCheckResourceAttr("google_dataproc_cluster.confidential", + "cluster_config.0.worker_config.0.min_cpu_platform", "AMD Rome"), + ), + }, + }, + }) +} + func TestAccDataprocCluster_withMetadataAndTags(t *testing.T) { t.Parallel() @@ -1400,7 +1443,7 @@ resource "google_dataproc_cluster" "virtual_cluster" { kubernetes_namespace = "tf-test-dproc-%s" kubernetes_software_config { component_version = { - "SPARK": "3.1-dataproc-7", + "SPARK": "3.5-dataproc-17", } } gke_cluster_config { @@ -1538,6 +1581,36 @@ resource "google_dataproc_cluster" "basic" { `, rnd, rnd, rnd, rnd) } +func testAccDataprocCluster_withConfidentialCompute(rnd, subnetworkName string, imageUri string) string { + return fmt.Sprintf(` +resource "google_dataproc_cluster" "confidential" { + name = "tf-test-dproc-%s" + region = "us-central1" + + cluster_config { + gce_cluster_config { + subnetwork = "%s" + confidential_instance_config { + enable_confidential_compute = true + } + } + + master_config { + machine_type = "n2d-standard-2" + image_uri = "%s" + min_cpu_platform = "AMD Rome" + } + + worker_config { + machine_type = "n2d-standard-2" + image_uri = "%s" + min_cpu_platform = "AMD Rome" + } + } +} +`, rnd, subnetworkName, imageUri, imageUri) +} + func testAccDataprocCluster_withMetadataAndTags(rnd, subnetworkName string) string { return fmt.Sprintf(` resource "google_dataproc_cluster" "basic" { diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job.go.tmpl b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job.go.tmpl index a60aade879d9..4fc7c56c3528 100644 --- a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job.go.tmpl +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job.go.tmpl @@ -929,11 +929,17 @@ func flattenHiveJob(job *dataproc.HiveJob) []map[string]interface{} { func expandHiveJob(config map[string]interface{}) *dataproc.HiveJob { job := &dataproc.HiveJob{} if v, ok := config["query_file_uri"]; ok { - job.QueryFileUri = v.(string) + queryFileUri := v.(string) + if len(queryFileUri) != 0 { + job.QueryFileUri = v.(string) + } } if v, ok := config["query_list"]; ok { - job.QueryList = &dataproc.QueryList{ - Queries: tpgresource.ConvertStringArr(v.([]interface{})), + queryList := v.([]interface{}) + if len(queryList) != 0 { + job.QueryList = &dataproc.QueryList{ + Queries: tpgresource.ConvertStringArr(queryList), + } } } if v, ok := config["continue_on_failure"]; ok { @@ -1037,11 +1043,17 @@ func flattenPigJob(job *dataproc.PigJob) []map[string]interface{} { func expandPigJob(config map[string]interface{}) *dataproc.PigJob { job := &dataproc.PigJob{} if v, ok := config["query_file_uri"]; ok { - job.QueryFileUri = v.(string) + queryFileUri := v.(string) + if len(queryFileUri) != 0 { + job.QueryFileUri = v.(string) + } } if v, ok := config["query_list"]; ok { - job.QueryList = &dataproc.QueryList{ - Queries: tpgresource.ConvertStringArr(v.([]interface{})), + queryList := v.([]interface{}) + if len(queryList) != 0 { + job.QueryList = &dataproc.QueryList{ + Queries: tpgresource.ConvertStringArr(queryList), + } } } if v, ok := config["continue_on_failure"]; ok { @@ -1138,11 +1150,17 @@ func flattenSparkSqlJob(job *dataproc.SparkSqlJob) []map[string]interface{} { func expandSparkSqlJob(config map[string]interface{}) *dataproc.SparkSqlJob { job := &dataproc.SparkSqlJob{} if v, ok := config["query_file_uri"]; ok { - job.QueryFileUri = v.(string) + queryFileUri := v.(string) + if len(queryFileUri) != 0 { + job.QueryFileUri = v.(string) + } } if v, ok := config["query_list"]; ok { - job.QueryList = &dataproc.QueryList{ - Queries: tpgresource.ConvertStringArr(v.([]interface{})), + queryList := v.([]interface{}) + if len(queryList) != 0 { + job.QueryList = &dataproc.QueryList{ + Queries: tpgresource.ConvertStringArr(queryList), + } } } if v, ok := config["script_variables"]; ok { @@ -1239,20 +1257,26 @@ func flattenPrestoJob(job *dataproc.PrestoJob) []map[string]interface{} { func expandPrestoJob(config map[string]interface{}) *dataproc.PrestoJob { job := &dataproc.PrestoJob{} + if v, ok := config["query_file_uri"]; ok { + queryFileUri := v.(string) + if len(queryFileUri) != 0 { + job.QueryFileUri = v.(string) + } + } + if v, ok := config["query_list"]; ok { + queryList := v.([]interface{}) + if len(queryList) != 0 { + job.QueryList = &dataproc.QueryList{ + Queries: tpgresource.ConvertStringArr(queryList), + } + } + } if v, ok := config["client_tags"]; ok { job.ClientTags = tpgresource.ConvertStringArr(v.([]interface{})) } if v, ok := config["continue_on_failure"]; ok { job.ContinueOnFailure = v.(bool) } - if v, ok := config["query_file_uri"]; ok { - job.QueryFileUri = v.(string) - } - if v, ok := config["query_list"]; ok { - job.QueryList = &dataproc.QueryList{ - Queries: tpgresource.ConvertStringArr(v.([]interface{})), - } - } if v, ok := config["properties"]; ok { job.Properties = tpgresource.ConvertStringMap(v.(map[string]interface{})) } diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_meta.yaml b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_meta.yaml new file mode 100644 index 000000000000..f791ce586f11 --- /dev/null +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_dataproc_job' +generation_type: 'handwritten' +api_service_name: 'dataproc.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Job' diff --git a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_test.go.tmpl b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_test.go.tmpl index 247e6b5c834b..9b6faf85a2d6 100644 --- a/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_test.go.tmpl +++ b/mmv1/third_party/terraform/services/dataproc/resource_dataproc_job_test.go.tmpl @@ -263,14 +263,9 @@ func TestAccDataprocJob_Pig(t *testing.T) { }) } -func TestAccDataprocJob_SparkSql(t *testing.T) { +func testAccDataprocJobSparkSql(t *testing.T, config string) { t.Parallel() - var job dataproc.Job - rnd := acctest.RandString(t, 10) - networkName := acctest.BootstrapSharedTestNetwork(t, "dataproc-cluster") - subnetworkName := acctest.BootstrapSubnet(t, "dataproc-cluster", networkName) - acctest.BootstrapFirewallForDataprocSharedNetwork(t, "dataproc-cluster", networkName) acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, @@ -278,7 +273,7 @@ func TestAccDataprocJob_SparkSql(t *testing.T) { CheckDestroy: testAccCheckDataprocJobDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccDataprocJob_sparksql(rnd, subnetworkName), + Config: config, Check: resource.ComposeTestCheckFunc( testAccCheckDataprocJobExists(t, "google_dataproc_job.sparksql", &job), @@ -299,6 +294,20 @@ func TestAccDataprocJob_SparkSql(t *testing.T) { }) } +func TestAccDataprocJob_SparkSql_QueryList(t *testing.T) { + rnd := acctest.RandString(t, 10) + networkName := acctest.BootstrapSharedTestNetwork(t, "dataproc-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "dataproc-cluster", networkName) + testAccDataprocJobSparkSql(t, testAccDataprocJob_SparkSql_QueryList(rnd, subnetworkName)) +} + +func TestAccDataprocJob_SparkSql_QueryFile(t *testing.T) { + rnd := acctest.RandString(t, 10) + networkName := acctest.BootstrapSharedTestNetwork(t, "dataproc-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "dataproc-cluster", networkName) + testAccDataprocJobSparkSql(t, testAccDataprocJob_SparkSql_QueryFile(rnd, subnetworkName)) +} + func TestAccDataprocJob_Presto(t *testing.T) { t.Parallel() @@ -831,7 +840,7 @@ resource "google_dataproc_job" "pig" { } -func testAccDataprocJob_sparksql(rnd, subnetworkName string) string { +func testAccDataprocJob_SparkSql_QueryList(rnd, subnetworkName string) string { return fmt.Sprintf( singleNodeClusterConfig+` resource "google_dataproc_job" "sparksql" { @@ -853,6 +862,24 @@ resource "google_dataproc_job" "sparksql" { } +func testAccDataprocJob_SparkSql_QueryFile(rnd, subnetworkName string) string { + return fmt.Sprintf( + singleNodeClusterConfig+` +resource "google_dataproc_job" "sparksql" { + region = google_dataproc_cluster.basic.region + force_delete = true + placement { + cluster_name = google_dataproc_cluster.basic.name + } + + sparksql_config { + query_file_uri = "gs://dataproc-examples-2f10d78d114f6aaec76462e3c310f31f/src/spark-sql/natality/cigarette_correlations.sql" + } +} +`, rnd, subnetworkName) + +} + func testAccDataprocJob_presto(rnd, subnetworkName string) string { return fmt.Sprintf(` resource "google_dataproc_cluster" "basic" { diff --git a/mmv1/third_party/terraform/services/dns/resource_dns_record_set_meta.yaml.tmpl b/mmv1/third_party/terraform/services/dns/resource_dns_record_set_meta.yaml.tmpl new file mode 100644 index 000000000000..80ecb660dbc7 --- /dev/null +++ b/mmv1/third_party/terraform/services/dns/resource_dns_record_set_meta.yaml.tmpl @@ -0,0 +1,9 @@ +resource: 'google_dns_record_set' +generation_type: 'handwritten' +api_service_name: 'dns.googleapis.com' +{{- if ne $.TargetVersionName "ga" }} +api_version: 'v1beta2' +{{- else }} +api_version: 'v1' +{{- end }} +api_resource_type_kind: 'ResourceRecordSet' diff --git a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config.go.tmpl b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config.go.tmpl index cb8aef4a8a2d..0755b2f3740a 100644 --- a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config.go.tmpl @@ -5,7 +5,7 @@ import ( "context" "fmt" - "google.golang.org/api/firebase/v1beta1" + firebase "google.golang.org/api/firebase/v1beta1" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -13,8 +13,9 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/fwresource" + "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the implementation satisfies the expected interfaces @@ -29,8 +30,8 @@ func NewGoogleFirebaseAndroidAppConfigDataSource() datasource.DataSource { // GoogleFirebaseAndroidAppConfigDataSource defines the data source implementation type GoogleFirebaseAndroidAppConfigDataSource struct { - client *firebase.Service - project types.String + client *firebase.Service + providerConfig *transport_tpg.Config } type GoogleFirebaseAndroidAppConfigModel struct { @@ -91,20 +92,20 @@ func (d *GoogleFirebaseAndroidAppConfigDataSource) Configure(ctx context.Context return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } - d.client = p.NewFirebaseClient(p.UserAgent, &resp.Diagnostics) + d.client = p.NewFirebaseClient(ctx, p.UserAgent) if resp.Diagnostics.HasError() { return } - d.project = p.Project + d.providerConfig = p } func (d *GoogleFirebaseAndroidAppConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { @@ -126,7 +127,7 @@ func (d *GoogleFirebaseAndroidAppConfigDataSource) Read(ctx context.Context, req // Use provider_meta to set User-Agent d.client.UserAgent = fwtransport.GenerateFrameworkUserAgentString(metaData, d.client.UserAgent) - data.Project = fwresource.GetProjectFramework(data.Project, d.project, &resp.Diagnostics) + data.Project = fwresource.GetProjectFramework(data.Project, types.StringValue(d.providerConfig.Project), &resp.Diagnostics) if resp.Diagnostics.HasError() { return } diff --git a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config_test.go.tmpl b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config_test.go.tmpl index dc799efdc85d..7280759962b9 100644 --- a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config_test.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_android_app_config_test.go.tmpl @@ -11,8 +11,6 @@ import ( func TestAccDataSourceGoogleFirebaseAndroidAppConfig(t *testing.T) { t.Parallel() - // Framework-based resources and datasources don't work with VCR yet - acctest.SkipIfVcr(t) context := map[string]interface{}{ "project_id": envvar.GetTestProjectFromEnv(), diff --git a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config.go.tmpl b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config.go.tmpl index 69d1da3451ea..8dfdf61f9dc2 100644 --- a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config.go.tmpl @@ -5,7 +5,7 @@ import ( "context" "fmt" - "google.golang.org/api/firebase/v1beta1" + firebase "google.golang.org/api/firebase/v1beta1" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwresource" "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the implementation satisfies the expected interfaces @@ -29,8 +30,8 @@ func NewGoogleFirebaseAppleAppConfigDataSource() datasource.DataSource { // GoogleFirebaseAppleAppConfigDataSource defines the data source implementation type GoogleFirebaseAppleAppConfigDataSource struct { - client *firebase.Service - project types.String + client *firebase.Service + providerConfig *transport_tpg.Config } type GoogleFirebaseAppleAppConfigModel struct { @@ -91,20 +92,20 @@ func (d *GoogleFirebaseAppleAppConfigDataSource) Configure(ctx context.Context, return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } - d.client = p.NewFirebaseClient(p.UserAgent, &resp.Diagnostics) + d.client = p.NewFirebaseClient(ctx, p.UserAgent) if resp.Diagnostics.HasError() { return } - d.project = p.Project + d.providerConfig = p } func (d *GoogleFirebaseAppleAppConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { @@ -126,7 +127,7 @@ func (d *GoogleFirebaseAppleAppConfigDataSource) Read(ctx context.Context, req d // Use provider_meta to set User-Agent d.client.UserAgent = fwtransport.GenerateFrameworkUserAgentString(metaData, d.client.UserAgent) - data.Project = fwresource.GetProjectFramework(data.Project, d.project, &resp.Diagnostics) + data.Project = fwresource.GetProjectFramework(data.Project, types.StringValue(d.providerConfig.Project), &resp.Diagnostics) if resp.Diagnostics.HasError() { return } diff --git a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config_test.go.tmpl b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config_test.go.tmpl index c71113abac3e..f94c796b6759 100644 --- a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config_test.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_apple_app_config_test.go.tmpl @@ -10,8 +10,6 @@ import ( ) func TestAccDataSourceGoogleFirebaseAppleAppConfig(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() context := map[string]interface{}{ @@ -23,20 +21,9 @@ func TestAccDataSourceGoogleFirebaseAppleAppConfig(t *testing.T) { } acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, + CheckDestroy: testAccCheckFirebaseAppleAppDestroyProducer(t), Steps: []resource.TestStep{ - { - ExternalProviders: map[string]resource.ExternalProvider{ - "google": { - VersionConstraint: "4.58.0", - Source: "hashicorp/google{{- if ne $.TargetVersionName "ga" -}}-{{$.TargetVersionName}}{{- end }}", - }, - }, - Config: testAccDataSourceGoogleFirebaseAppleAppConfig(context), - Check: resource.ComposeTestCheckFunc( - testAccDataSourceFirebaseAppleAppConfigCheck("data.google_firebase_apple_app_config.my_app_config"), - ), - }, { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Config: testAccDataSourceGoogleFirebaseAppleAppConfig(context), diff --git a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_web_app_config.go.tmpl b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_web_app_config.go.tmpl index 8782d08fdbc7..7626b3d5b902 100644 --- a/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_web_app_config.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/data_source_google_firebase_web_app_config.go.tmpl @@ -5,7 +5,7 @@ import ( "context" "fmt" - "google.golang.org/api/firebase/v1beta1" + firebase "google.golang.org/api/firebase/v1beta1" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwresource" "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the implementation satisfies the expected interfaces @@ -29,8 +30,8 @@ func NewGoogleFirebaseWebAppConfigDataSource() datasource.DataSource { // GoogleFirebaseWebAppConfigDataSource defines the data source implementation type GoogleFirebaseWebAppConfigDataSource struct { - client *firebase.Service - project types.String + client *firebase.Service + providerConfig *transport_tpg.Config } type GoogleFirebaseWebAppConfigModel struct { @@ -138,20 +139,20 @@ func (d *GoogleFirebaseWebAppConfigDataSource) Configure(ctx context.Context, re return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } - d.client = p.NewFirebaseClient(p.UserAgent, &resp.Diagnostics) + d.client = p.NewFirebaseClient(ctx, p.UserAgent) if resp.Diagnostics.HasError() { return } - d.project = p.Project + d.providerConfig = p } func (d *GoogleFirebaseWebAppConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { @@ -173,7 +174,7 @@ func (d *GoogleFirebaseWebAppConfigDataSource) Read(ctx context.Context, req dat // Use provider_meta to set User-Agent d.client.UserAgent = fwtransport.GenerateFrameworkUserAgentString(metaData, d.client.UserAgent) - data.Project = fwresource.GetProjectFramework(data.Project, d.project, &resp.Diagnostics) + data.Project = fwresource.GetProjectFramework(data.Project, types.StringValue(d.providerConfig.Project), &resp.Diagnostics) if resp.Diagnostics.HasError() { return } diff --git a/mmv1/third_party/terraform/services/firebase/resource_firebase_web_app_test.go.tmpl b/mmv1/third_party/terraform/services/firebase/resource_firebase_web_app_test.go.tmpl index 8106154a2bff..8a932269376b 100644 --- a/mmv1/third_party/terraform/services/firebase/resource_firebase_web_app_test.go.tmpl +++ b/mmv1/third_party/terraform/services/firebase/resource_firebase_web_app_test.go.tmpl @@ -16,8 +16,6 @@ import ( ) func TestAccFirebaseWebApp_firebaseWebAppFull(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() context := map[string]interface{}{ diff --git a/mmv1/third_party/terraform/services/gemini/iam_gemini_repository_group_test.go.tmpl b/mmv1/third_party/terraform/services/gemini/iam_gemini_repository_group_test.go.tmpl new file mode 100644 index 000000000000..97f2c7a51308 --- /dev/null +++ b/mmv1/third_party/terraform/services/gemini/iam_gemini_repository_group_test.go.tmpl @@ -0,0 +1,290 @@ +package gemini_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +// To run tests locally please replace the `oauth_token_secret_version` with your secret manager version. +// More details: https://cloud.google.com/developer-connect/docs/connect-github-repo#before_you_begin + +func TestAccGeminiRepositoryGroupIamBinding(t *testing.T) { + location := "us-central1" + codeRepositoryIndexId := acctest.BootstrapSharedCodeRepositoryIndex(t, "basic", location, "", map[string]string{"ccfe_debug_note": "terraform_e2e_should_be_deleted"}) + developerConnectionId := acctest.BootstrapDeveloperConnection(t, "basic", location, "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648) + gitRepositoryLinkId := acctest.BootstrapGitRepository(t, "basic", location, "https://github.com/CC-R-github-robot/tf-test.git", developerConnectionId) + repositoryGroupId := "tf-test-iam-repository-group-id-" + acctest.RandString(t, 10) + + context := map[string]interface{}{ + "role": "roles/cloudaicompanion.repositoryGroupsUser", + "code_repository_index": codeRepositoryIndexId, + "location": location, + "project": envvar.GetTestProjectFromEnv(), + "connection_id": developerConnectionId, + "git_link_id": gitRepositoryLinkId, + "repository_group_id": repositoryGroupId, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiRepositoryGroupIamBinding_basic(context), + }, + { + ResourceName: "google_gemini_repository_group_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s roles/cloudaicompanion.repositoryGroupsUser", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), codeRepositoryIndexId, repositoryGroupId), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccGeminiRepositoryGroupIamBinding_update(context), + }, + { + ResourceName: "google_gemini_repository_group_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s roles/cloudaicompanion.repositoryGroupsUser", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), codeRepositoryIndexId, repositoryGroupId), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccGeminiRepositoryGroupIamMember(t *testing.T) { + location := "us-central1" + codeRepositoryIndexId := acctest.BootstrapSharedCodeRepositoryIndex(t, "basic", location, "", map[string]string{"ccfe_debug_note": "terraform_e2e_should_be_deleted"}) + developerConnectionId := acctest.BootstrapDeveloperConnection(t, "basic", location, "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648) + gitRepositoryLinkId := acctest.BootstrapGitRepository(t, "basic", location, "https://github.com/CC-R-github-robot/tf-test.git", developerConnectionId) + repositoryGroupId := "tf-test-iam-repository-group-id-" + acctest.RandString(t, 10) + + context := map[string]interface{}{ + "role": "roles/cloudaicompanion.repositoryGroupsUser", + "code_repository_index": codeRepositoryIndexId, + "location": location, + "project": envvar.GetTestProjectFromEnv(), + "connection_id": developerConnectionId, + "git_link_id": gitRepositoryLinkId, + "repository_group_id": repositoryGroupId, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccGeminiRepositoryGroupIamMember_basic(context), + }, + { + ResourceName: "google_gemini_repository_group_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s roles/cloudaicompanion.repositoryGroupsUser user:admin@hashicorptest.com", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), codeRepositoryIndexId, repositoryGroupId), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccGeminiRepositoryGroupIamPolicy(t *testing.T) { + location := "us-central1" + codeRepositoryIndexId := acctest.BootstrapSharedCodeRepositoryIndex(t, "basic", location, "", map[string]string{"ccfe_debug_note": "terraform_e2e_should_be_deleted"}) + developerConnectionId := acctest.BootstrapDeveloperConnection(t, "basic", location, "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1", 54180648) + gitRepositoryLinkId := acctest.BootstrapGitRepository(t, "basic", location, "https://github.com/CC-R-github-robot/tf-test.git", developerConnectionId) + repositoryGroupId := "tf-test-iam-repository-group-id-" + acctest.RandString(t, 10) + + context := map[string]interface{}{ + "role": "roles/cloudaicompanion.repositoryGroupsUser", + "code_repository_index": codeRepositoryIndexId, + "location": location, + "project": envvar.GetTestProjectFromEnv(), + "connection_id": developerConnectionId, + "git_link_id": gitRepositoryLinkId, + "repository_group_id": repositoryGroupId, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiRepositoryGroupIamPolicy_basic(context), + Check: resource.TestCheckResourceAttrSet("data.google_gemini_repository_group_iam_policy.foo", "policy_data"), + }, + { + ResourceName: "google_gemini_repository_group_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), codeRepositoryIndexId, repositoryGroupId), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccGeminiRepositoryGroupIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_gemini_repository_group_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), codeRepositoryIndexId, repositoryGroupId), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccGeminiRepositoryGroupIamMember_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group_iam_member" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "%{repository_group_id}" + repositories { + resource = "projects/%{project}/locations/us-central1/connections/%{connection_id}/gitRepositoryLinks/%{git_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} +`, context) +} + +func testAccGeminiRepositoryGroupIamPolicy_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_iam_policy" "foo" { + provider = google-beta + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_gemini_repository_group_iam_policy" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + policy_data = data.google_iam_policy.foo.policy_data +} + +data "google_gemini_repository_group_iam_policy" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + depends_on = [ + google_gemini_repository_group_iam_policy.foo + ] +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "%{repository_group_id}" + repositories { + resource = "projects/%{project}/locations/us-central1/connections/%{connection_id}/gitRepositoryLinks/%{git_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} +`, context) +} + +func testAccGeminiRepositoryGroupIamPolicy_emptyBinding(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_iam_policy" "foo" { + provider = google-beta +} + +resource "google_gemini_repository_group_iam_policy" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + policy_data = data.google_iam_policy.foo.policy_data +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "%{repository_group_id}" + repositories { + resource = "projects/%{project}/locations/us-central1/connections/%{connection_id}/gitRepositoryLinks/%{git_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} +`, context) +} + +func testAccGeminiRepositoryGroupIamBinding_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group_iam_binding" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "%{repository_group_id}" + repositories { + resource = "projects/%{project}/locations/us-central1/connections/%{connection_id}/gitRepositoryLinks/%{git_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} +`, context) +} + +func testAccGeminiRepositoryGroupIamBinding_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group_iam_binding" "foo" { + provider = google-beta + project = "%{project}" + location = "%{location}" + code_repository_index = "%{code_repository_index}" + repository_group_id = google_gemini_repository_group.example.repository_group_id + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} + +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "%{repository_group_id}" + repositories { + resource = "projects/%{project}/locations/us-central1/connections/%{connection_id}/gitRepositoryLinks/%{git_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} +`, context) +} +{{ end }} diff --git a/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl b/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl new file mode 100644 index 000000000000..ab1520dbc92b --- /dev/null +++ b/mmv1/third_party/terraform/services/gemini/resource_gemini_code_repository_index_test.go.tmpl @@ -0,0 +1,84 @@ +package gemini_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccGeminiCodeRepositoryIndex_update(t *testing.T) { + bootstrappedKMS := acctest.BootstrapKMSKeyInLocation(t, "us-central1") + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "project_id": os.Getenv("GOOGLE_PROJECT"), + "kms_key": bootstrappedKMS.CryptoKey.Name, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiCodeRepositoryIndex_basic(context), + }, + { + ResourceName: "google_gemini_code_repository_index.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index_id", "labels", "location", "terraform_labels"}, + }, + { + Config: testAccGeminiCodeRepositoryIndex_update(context), + }, + { + ResourceName: "google_gemini_code_repository_index.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index_id", "labels", "location", "terraform_labels"}, + }, + }, + }) +} + +func testAccGeminiCodeRepositoryIndex_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_code_repository_index" "example" { + provider = google-beta + labels = {"ccfe_debug_note": "terraform_e2e_should_be_deleted"} + location = "us-central1" + code_repository_index_id = "tf-test-cri-index-example-%{random_suffix}" + kms_key = "%{kms_key}" + depends_on = [google_kms_crypto_key_iam_binding.crypto_key_binding] +} + +data "google_project" "project" { + provider = google-beta +} + +resource "google_kms_crypto_key_iam_binding" "crypto_key_binding" { + provider = google-beta + crypto_key_id = "%{kms_key}" + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-cloudaicompanion.iam.gserviceaccount.com", + ] +} +`, context) +} + +func testAccGeminiCodeRepositoryIndex_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_code_repository_index" "example" { + provider = google-beta + labels = {"ccfe_debug_note": "terraform_e2e_should_be_deleted", "new_label": "new_val"} + location = "us-central1" + code_repository_index_id = "tf-test-cri-index-example-%{random_suffix}" + kms_key = "%{kms_key}" +} +`, context) +} +{{ end }} diff --git a/mmv1/third_party/terraform/services/gemini/resource_gemini_repository_group_test.go.tmpl b/mmv1/third_party/terraform/services/gemini/resource_gemini_repository_group_test.go.tmpl new file mode 100644 index 000000000000..931e861b908e --- /dev/null +++ b/mmv1/third_party/terraform/services/gemini/resource_gemini_repository_group_test.go.tmpl @@ -0,0 +1,249 @@ +package gemini_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +// To run tests locally please replace the `oauth_token_secret_version` with your secret manager version. +// More details: https://cloud.google.com/developer-connect/docs/connect-github-repo#before_you_begin + +func TestAccGeminiRepositoryGroup_update(t *testing.T) { + codeRepositoryIndexId := acctest.BootstrapSharedCodeRepositoryIndex(t, "basic-rg-test", "us-central1", "", map[string]string{"ccfe_debug_note": "terraform_e2e_should_be_deleted"}) + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "project_id": os.Getenv("GOOGLE_PROJECT"), + "code_repository_index": codeRepositoryIndexId, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiRepositoryGroup_basic(context), + }, + { + ResourceName: "google_gemini_repository_group.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index", "labels", "location", "repository_group_id", "terraform_labels"}, + }, + { + Config: testAccGeminiRepositoryGroup_update(context), + }, + { + ResourceName: "google_gemini_repository_group.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index", "labels", "location", "repository_group_id", "terraform_labels"}, + }, + }, + }) +} + +func TestAccGeminiRepositoryGroup_noBootstrap(t *testing.T) { + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "project_id": os.Getenv("GOOGLE_PROJECT"), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccGeminiRepositoryGroup_noBootstrap(context), + }, + { + ResourceName: "google_gemini_repository_group.example_e", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"code_repository_index", "labels", "location", "repository_group_id", "terraform_labels"}, + }, + }, + }) +} + +func testAccGeminiRepositoryGroup_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "tf-test-rg-repository-group-id-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_developer_connect_git_repository_link" "conn" { + provider = google-beta + git_repository_link_id = "tf-test-repository-conn" + parent_connection = google_developer_connect_connection.github_conn.connection_id + clone_uri = "https://github.com/CC-R-github-robot/tf-test.git" + location = "us-central1" + annotations = {} +} + +resource "google_developer_connect_connection" "github_conn" { + provider = google-beta + location = "us-central1" + connection_id = "tf-test-cloudaicompanion2-%{random_suffix}" + disabled = false + + github_config { + github_app = "DEVELOPER_CONNECT" + app_installation_id = 54180648 + + authorizer_credential { + oauth_token_secret_version = "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1" + } + } +} +`, context) +} +func testAccGeminiRepositoryGroup_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_repository_group" "example" { + provider = google-beta + location = "us-central1" + code_repository_index = "%{code_repository_index}" + repository_group_id = "tf-test-rg-repository-group-id-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1", "label2": "value2"} +} + +resource "google_developer_connect_git_repository_link" "conn" { + provider = google-beta + git_repository_link_id = "tf-test-repository-conn" + parent_connection = google_developer_connect_connection.github_conn.connection_id + clone_uri = "https://github.com/CC-R-github-robot/tf-test.git" + location = "us-central1" + annotations = {} +} + +resource "google_developer_connect_connection" "github_conn" { + provider = google-beta + location = "us-central1" + connection_id = "tf-test-cloudaicompanion3-%{random_suffix}" + disabled = false + + github_config { + github_app = "DEVELOPER_CONNECT" + app_installation_id = 54180648 + + authorizer_credential { + oauth_token_secret_version = "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1" + } + } +} +`, context) +} + +func testAccGeminiRepositoryGroup_noBootstrap(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_gemini_code_repository_index" "cri" { + provider = google-beta + labels = {"ccfe_debug_note": "terraform_e2e_should_be_deleted"} + location = "us-central1" + code_repository_index_id = "tf-test-rg-index-example-%{random_suffix}" +} + +resource "google_gemini_repository_group" "example_a" { + provider = google-beta + location = "us-central1" + code_repository_index = google_gemini_code_repository_index.cri.code_repository_index_id + repository_group_id = "tf-test-rg-nb-repository-group-id1-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_gemini_repository_group" "example_b" { + provider = google-beta + location = "us-central1" + code_repository_index = google_gemini_code_repository_index.cri.code_repository_index_id + repository_group_id = "tf-test-rg-nb-repository-group-id2-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_gemini_repository_group" "example_c" { + provider = google-beta + location = "us-central1" + code_repository_index = google_gemini_code_repository_index.cri.code_repository_index_id + repository_group_id = "tf-test-rg-nb-repository-group-id3-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_gemini_repository_group" "example_d" { + provider = google-beta + location = "us-central1" + code_repository_index = google_gemini_code_repository_index.cri.code_repository_index_id + repository_group_id = "tf-test-rg-nb-repository-group-id4-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_gemini_repository_group" "example_e" { + provider = google-beta + location = "us-central1" + code_repository_index = google_gemini_code_repository_index.cri.code_repository_index_id + repository_group_id = "tf-test-rg-nb-repository-group-id5-%{random_suffix}" + repositories { + resource = "projects/%{project_id}/locations/us-central1/connections/${google_developer_connect_connection.github_conn.connection_id}/gitRepositoryLinks/${google_developer_connect_git_repository_link.conn.git_repository_link_id}" + branch_pattern = "main" + } + labels = {"label1": "value1"} +} + +resource "google_developer_connect_git_repository_link" "conn" { + provider = google-beta + git_repository_link_id = "tf-test-repository-conn" + parent_connection = google_developer_connect_connection.github_conn.connection_id + clone_uri = "https://github.com/CC-R-github-robot/tf-test.git" + location = "us-central1" + annotations = {} +} + +resource "google_developer_connect_connection" "github_conn" { + provider = google-beta + location = "us-central1" + connection_id = "tf-test-cloudaicompanion1-%{random_suffix}" + disabled = false + + github_config { + github_app = "DEVELOPER_CONNECT" + app_installation_id = 54180648 + + authorizer_credential { + oauth_token_secret_version = "projects/502367051001/secrets/tf-test-cloudaicompanion-github-oauthtoken-c42e5c/versions/1" + } + } +} +`, context) +} +{{ end }} diff --git a/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.tmpl b/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.tmpl index febea4dd172f..1ef469b85e42 100644 --- a/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.tmpl +++ b/mmv1/third_party/terraform/services/gkehub/resource_gke_hub_feature_membership_test.go.tmpl @@ -160,9 +160,9 @@ resource "google_gke_hub_feature_membership" "feature_member_1" { feature = google_gke_hub_feature.feature.name membership = google_gke_hub_membership.membership.membership_id configmanagement { - version = "1.18.2" config_sync { source_format = "hierarchy" + stop_syncing = true enabled = true git { sync_repo = "https://github.com/GoogleCloudPlatform/magic-modules" @@ -409,6 +409,7 @@ resource "google_gke_hub_feature_membership" "feature_member" { sync_rev = "v3.60.0" sync_wait_secs = "30" } + stop_syncing = true } } } diff --git a/mmv1/third_party/terraform/services/iam3/resource_iam_folders_policy_binding_test.go.tmpl b/mmv1/third_party/terraform/services/iam3/resource_iam_folders_policy_binding_test.go.tmpl index c64a779ed07e..8dedbe2d98f7 100644 --- a/mmv1/third_party/terraform/services/iam3/resource_iam_folders_policy_binding_test.go.tmpl +++ b/mmv1/third_party/terraform/services/iam3/resource_iam_folders_policy_binding_test.go.tmpl @@ -1,5 +1,4 @@ package iam3_test -{{- if ne $.TargetVersionName "ga" }} import ( "testing" @@ -20,7 +19,7 @@ func TestAccIAM3FoldersPolicyBinding_iamFoldersPolicyBindingExample_update(t *te acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), ExternalProviders: map[string]resource.ExternalProvider{ "time": {}, }, @@ -51,7 +50,6 @@ func TestAccIAM3FoldersPolicyBinding_iamFoldersPolicyBindingExample_update(t *te func testAccIAM3FoldersPolicyBinding_iamFoldersPolicyBindingExample_full(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test folder binding%{random_suffix}" @@ -59,7 +57,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_folder" "folder" { - provider = google-beta display_name = "test folder%{random_suffix}" parent = "organizations/%{org_id}" deletion_protection = false @@ -71,7 +68,6 @@ resource "time_sleep" "wait_120s" { } resource "google_iam_folders_policy_binding" "my-folder-binding" { - provider = google-beta folder = google_folder.folder.folder_id location = "global" display_name = "test folder binding%{random_suffix}" @@ -89,7 +85,6 @@ resource "google_iam_folders_policy_binding" "my-folder-binding" { func testAccIAM3FoldersPolicyBinding_iamFoldersPolicyBindingExample_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test folder binding%{random_suffix}" @@ -97,7 +92,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_folder" "folder" { - provider = google-beta display_name = "test folder%{random_suffix}" parent = "organizations/%{org_id}" deletion_protection = false @@ -109,7 +103,6 @@ resource "time_sleep" "wait_120s" { } resource "google_iam_folders_policy_binding" "my-folder-binding" { - provider = google-beta folder = google_folder.folder.folder_id location = "global" display_name = "test folder binding%{random_suffix}" @@ -130,5 +123,3 @@ resource "google_iam_folders_policy_binding" "my-folder-binding" { } `, context) } - -{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/iam3/resource_iam_organizations_policy_binding_test.go.tmpl b/mmv1/third_party/terraform/services/iam3/resource_iam_organizations_policy_binding_test.go.tmpl index 0c2d9564ed25..6c11a1e40fad 100644 --- a/mmv1/third_party/terraform/services/iam3/resource_iam_organizations_policy_binding_test.go.tmpl +++ b/mmv1/third_party/terraform/services/iam3/resource_iam_organizations_policy_binding_test.go.tmpl @@ -1,5 +1,4 @@ package iam3_test -{{- if ne $.TargetVersionName "ga" }} import ( "testing" @@ -20,7 +19,7 @@ func TestAccIAM3OrganizationsPolicyBinding_iam3OrganizationsPolicyBindingExample acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckIAM3OrganizationsPolicyBindingDestroyProducer(t), Steps: []resource.TestStep{ { @@ -49,7 +48,6 @@ func TestAccIAM3OrganizationsPolicyBinding_iam3OrganizationsPolicyBindingExample func testAccIAM3OrganizationsPolicyBinding_iam3OrganizationsPolicyBindingExample_full(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test org binding%{random_suffix}" @@ -57,7 +55,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_iam_organizations_policy_binding" "my_org_binding" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test org binding%{random_suffix}" @@ -74,7 +71,6 @@ resource "google_iam_organizations_policy_binding" "my_org_binding" { func testAccIAM3OrganizationsPolicyBinding_iam3OrganizationsPolicyBindingExample_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_principal_access_boundary_policy" "pab_policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test org binding%{random_suffix}" @@ -82,7 +78,6 @@ resource "google_iam_principal_access_boundary_policy" "pab_policy" { } resource "google_iam_organizations_policy_binding" "my_org_binding" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test org binding%{random_suffix}" @@ -102,4 +97,3 @@ resource "google_iam_organizations_policy_binding" "my_org_binding" { } `, context) } -{{- end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/iam3/resource_iam_principal_access_boundary_policy_test.go.tmpl b/mmv1/third_party/terraform/services/iam3/resource_iam_principal_access_boundary_policy_test.go.tmpl index 39bd480e9cc6..5603b10a2b9f 100644 --- a/mmv1/third_party/terraform/services/iam3/resource_iam_principal_access_boundary_policy_test.go.tmpl +++ b/mmv1/third_party/terraform/services/iam3/resource_iam_principal_access_boundary_policy_test.go.tmpl @@ -1,6 +1,4 @@ package iam3_test -{{- if ne $.TargetVersionName "ga" }} - import ( "testing" @@ -19,7 +17,7 @@ func TestAccIAM3PrincipalAccessBoundaryPolicy_iam3PrincipalAccessBoundaryPolicyE acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccCheckIAM3PrincipalAccessBoundaryPolicyDestroyProducer(t), Steps: []resource.TestStep{ { @@ -47,7 +45,6 @@ func TestAccIAM3PrincipalAccessBoundaryPolicy_iam3PrincipalAccessBoundaryPolicyE func testAccIAM3PrincipalAccessBoundaryPolicy_iam3PrincipalAccessBoundaryPolicyExample_full(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_principal_access_boundary_policy" "my-pab-policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test pab policy%{random_suffix}" @@ -60,7 +57,6 @@ func testAccIAM3PrincipalAccessBoundaryPolicy_iam3PrincipalAccessBoundaryPolicyE return acctest.Nprintf(` resource "google_project" "project" { - provider = google-beta project_id = "tf-test%{random_suffix}" name = "tf-test%{random_suffix}" org_id = "%{org_id}" @@ -68,7 +64,6 @@ resource "google_project" "project" { } resource "google_iam_principal_access_boundary_policy" "my-pab-policy" { - provider = google-beta organization = "%{org_id}" location = "global" display_name = "test pab policy%{random_suffix}" @@ -85,4 +80,3 @@ resource "google_iam_principal_access_boundary_policy" "my-pab-policy" { } `, context) } -{{- end }} diff --git a/mmv1/third_party/terraform/services/iam3/resource_iam_projects_policy_binding_test.go.tmpl b/mmv1/third_party/terraform/services/iam3/resource_iam_projects_policy_binding_test.go.tmpl new file mode 100644 index 000000000000..5c6d4461bce5 --- /dev/null +++ b/mmv1/third_party/terraform/services/iam3/resource_iam_projects_policy_binding_test.go.tmpl @@ -0,0 +1,116 @@ +package iam3_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckIAM3ProjectsPolicyBindingDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_full(context), + }, + { + ResourceName: "google_iam_projects_policy_binding.my-project-binding", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"annotations", "location", "policy_binding_id"}, + }, + { + Config: testAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_update(context), + }, + { + ResourceName: "google_iam_projects_policy_binding.my-project-binding", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"annotations", "location", "policy_binding_id"}, + }, + { + Config: testAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_full(context), + }, + { + ResourceName: "google_iam_projects_policy_binding.my-project-binding", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"annotations", "location", "policy_binding_id"}, + }, + + }, + }) +} + +func testAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_principal_access_boundary_policy" "pab_policy" { + organization = "%{org_id}" + location = "global" + display_name = "test project binding%{random_suffix}" + principal_access_boundary_policy_id = "tf-test-my-pab-policy%{random_suffix}" +} + +data "google_project" "project" { + provider = google +} + +resource "google_iam_projects_policy_binding" "my-project-binding" { + project = data.google_project.project.project_id + location = "global" + display_name = "test project binding%{random_suffix}" + policy_kind = "PRINCIPAL_ACCESS_BOUNDARY" + policy_binding_id = "tf-test-project-binding%{random_suffix}" + policy = "organizations/%{org_id}/locations/global/principalAccessBoundaryPolicies/${google_iam_principal_access_boundary_policy.pab_policy.principal_access_boundary_policy_id}" + target { + principal_set = "//cloudresourcemanager.googleapis.com/projects/${data.google_project.project.project_id}" + } +} +`, context) +} + +func testAccIAM3ProjectsPolicyBinding_iamProjectsPolicyBindingExample_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_principal_access_boundary_policy" "pab_policy" { + organization = "%{org_id}" + location = "global" + display_name = "test project binding%{random_suffix}" + principal_access_boundary_policy_id = "tf-test-my-pab-policy%{random_suffix}" +} + +data "google_project" "project" { + provider = google +} + +resource "google_iam_projects_policy_binding" "my-project-binding" { + project = data.google_project.project.project_id + location = "global" + display_name = "test project binding%{random_suffix}" + policy_kind = "PRINCIPAL_ACCESS_BOUNDARY" + policy_binding_id = "tf-test-project-binding%{random_suffix}" + policy = "organizations/%{org_id}/locations/global/principalAccessBoundaryPolicies/${google_iam_principal_access_boundary_policy.pab_policy.principal_access_boundary_policy_id}" + annotations = {"foo": "bar"} + target { + principal_set = "//cloudresourcemanager.googleapis.com/projects/${data.google_project.project.project_id}" + } + condition { + description = "test condition" + expression = "principal.subject == 'al@a.com'" + location = "test location" + title = "test title" + } +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_bucket_config_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_bucket_config_meta.yaml new file mode 100644 index 000000000000..dde6b3bbbdae --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_bucket_config_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_billing_account_bucket_config' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogBucket' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_exclusion_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_exclusion_meta.yaml new file mode 100644 index 000000000000..ddf57dfcd9a5 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_exclusion_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_billing_account_exclusion' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogExclusion' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_sink_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_sink_meta.yaml new file mode 100644 index 000000000000..d4b53b3928c7 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_billing_account_sink_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_billing_account_sink' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogSink' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_folder_bucket_config_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_folder_bucket_config_meta.yaml new file mode 100644 index 000000000000..0cb7b8ed2b5d --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_folder_bucket_config_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_folder_bucket_config' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogBucket' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_folder_exclusion_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_folder_exclusion_meta.yaml new file mode 100644 index 000000000000..6a28fc914715 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_folder_exclusion_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_folder_exclusion' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogExclusion' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_folder_sink_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_folder_sink_meta.yaml new file mode 100644 index 000000000000..9cbbdbe7bfd2 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_folder_sink_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_folder_sink' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogSink' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_organization_bucket_config_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_organization_bucket_config_meta.yaml new file mode 100644 index 000000000000..360364a63c13 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_organization_bucket_config_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_organization_bucket_config' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogBucket' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_organization_exclusion_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_organization_exclusion_meta.yaml new file mode 100644 index 000000000000..38fa6d3bbe2f --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_organization_exclusion_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_organization_exclusion' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogExclusion' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_organization_sink_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_organization_sink_meta.yaml new file mode 100644 index 000000000000..e15619ac6042 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_organization_sink_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_organization_sink' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogSink' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_project_bucket_config_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_project_bucket_config_meta.yaml new file mode 100644 index 000000000000..04cee781e95a --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_project_bucket_config_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_project_bucket_config' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogBucket' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_project_exclusion_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_project_exclusion_meta.yaml new file mode 100644 index 000000000000..a4f8f1818ea3 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_project_exclusion_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_project_exclusion' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogExclusion' diff --git a/mmv1/third_party/terraform/services/logging/resource_logging_project_sink_meta.yaml b/mmv1/third_party/terraform/services/logging/resource_logging_project_sink_meta.yaml new file mode 100644 index 000000000000..edbc61496f71 --- /dev/null +++ b/mmv1/third_party/terraform/services/logging/resource_logging_project_sink_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_logging_project_sink' +generation_type: 'handwritten' +api_service_name: 'logging.googleapis.com' +api_version: 'v2' +api_resource_type_kind: 'LogSink' diff --git a/mmv1/third_party/terraform/services/monitoring/resource_monitoring_alert_policy_test.go b/mmv1/third_party/terraform/services/monitoring/resource_monitoring_alert_policy_test.go index e3ec6583d1d8..72814cf03c2c 100644 --- a/mmv1/third_party/terraform/services/monitoring/resource_monitoring_alert_policy_test.go +++ b/mmv1/third_party/terraform/services/monitoring/resource_monitoring_alert_policy_test.go @@ -461,6 +461,7 @@ resource "google_monitoring_alert_policy" "promql" { } alert_rule = "AlwaysOn" rule_group = "abc" + disable_metric_validation = true } } diff --git a/mmv1/third_party/terraform/services/monitoring/resource_monitoring_dashboard_meta.yaml b/mmv1/third_party/terraform/services/monitoring/resource_monitoring_dashboard_meta.yaml new file mode 100644 index 000000000000..626228ebebb4 --- /dev/null +++ b/mmv1/third_party/terraform/services/monitoring/resource_monitoring_dashboard_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_monitoring_dashboard' +generation_type: 'handwritten' +api_service_name: 'monitoring.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Dashboard' diff --git a/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go index 45f465ce0797..6925ec048983 100644 --- a/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go +++ b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go @@ -618,7 +618,7 @@ func testAccNetappVolume_volumeBasicExample_cleanupScheduledBackup(t *testing.T, createTime time.Time } var backupDataList []BackupData - for i, _ := range backups { + for i := range backups { backup := backups[i].(map[string]interface{}) backupName := backup["name"].(string) backupCreateTimeStr := backup["createTime"].(string) @@ -635,7 +635,7 @@ func testAccNetappVolume_volumeBasicExample_cleanupScheduledBackup(t *testing.T, sort.Slice(backupDataList, func(i, j int) bool { return backupDataList[i].createTime.After(backupDataList[j].createTime) }) - for i, _ := range backupDataList { + for i := range backupDataList { baseUrl, err := tpgresource.ReplaceVarsForTest(config, rs, "{{NetappBasePath}}") if err != nil { return fmt.Errorf("Error : %v", err) diff --git a/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_test.go b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_test.go index 91f7956ba370..9c28e20a50f9 100644 --- a/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_test.go +++ b/mmv1/third_party/terraform/services/networkconnectivity/resource_network_connectivity_spoke_test.go @@ -112,6 +112,15 @@ func TestAccNetworkConnectivitySpoke_RouterApplianceHandWritten(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, + { + Config: testAccNetworkConnectivitySpoke_RouterApplianceHandWrittenUpdate1(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, }, }) } @@ -148,9 +157,91 @@ func TestAccNetworkConnectivitySpoke_RouterApplianceHandWrittenLongForm(t *testi ImportStateVerify: true, ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, + { + Config: testAccNetworkConnectivitySpoke_RouterApplianceHandWrittenUpdate1LongForm(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, }, }) } + +func TestAccNetworkConnectivitySpoke_VPNTunnelHandWrittenHandWritten(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_name": envvar.GetTestProjectFromEnv(), + "region": envvar.GetTestRegionFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkConnectivitySpokeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkConnectivitySpoke_VPNTunnelHandWrittenHandWritten(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkConnectivitySpoke_VPNTunnelHandWrittenHandWrittenUpdate0(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + }, + }) +} + +func TestAccNetworkConnectivitySpoke_InterconnectAttachmentHandWrittenHandWritten(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_name": envvar.GetTestProjectFromEnv(), + "region": envvar.GetTestRegionFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkConnectivitySpokeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkConnectivitySpoke_InterconnectAttachmentHandWrittenHandWritten(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkConnectivitySpoke_InterconnectAttachmentHandWrittenHandWrittenUpdate0(context), + }, + { + ResourceName: "google_network_connectivity_spoke.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + }, + }) +} + func testAccNetworkConnectivitySpoke_LinkedVPCNetworkHandWritten(context map[string]interface{}) string { return acctest.Nprintf(` @@ -244,8 +335,8 @@ resource "google_compute_subnetwork" "subnetwork" { network = google_compute_network.network.self_link } -resource "google_compute_instance" "instance" { - name = "tf-test-instance%{random_suffix}" +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" machine_type = "e2-medium" can_ip_forward = true zone = "%{zone}" @@ -276,14 +367,14 @@ resource "google_network_connectivity_hub" "basic_hub" { resource "google_network_connectivity_spoke" "primary" { name = "tf-test-name%{random_suffix}" location = "%{region}" - description = "A sample spoke with a linked routher appliance instance" + description = "A sample spoke with a single linked routher appliance instance" labels = { label-one = "value-one" } hub = google_network_connectivity_hub.basic_hub.id linked_router_appliance_instances { instances { - virtual_machine = google_compute_instance.instance.self_link + virtual_machine = google_compute_instance.router-instance1.self_link ip_address = "10.0.0.2" } site_to_site_data_transfer = true @@ -307,8 +398,8 @@ resource "google_compute_subnetwork" "subnetwork" { network = google_compute_network.network.self_link } -resource "google_compute_instance" "instance" { - name = "tf-test-instance%{random_suffix}" +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" machine_type = "e2-medium" can_ip_forward = true zone = "%{zone}" @@ -339,14 +430,14 @@ resource "google_network_connectivity_hub" "basic_hub" { resource "google_network_connectivity_spoke" "primary" { name = "tf-test-name%{random_suffix}" location = "%{region}" - description = "An UPDATED sample spoke with a linked routher appliance instance" + description = "An UPDATED sample spoke with a single linked routher appliance instance" labels = { label-two = "value-two" } hub = google_network_connectivity_hub.basic_hub.id linked_router_appliance_instances { instances { - virtual_machine = google_compute_instance.instance.self_link + virtual_machine = google_compute_instance.router-instance1.self_link ip_address = "10.0.0.2" } site_to_site_data_transfer = true @@ -354,6 +445,96 @@ resource "google_network_connectivity_spoke" "primary" { } `, context) } + +func testAccNetworkConnectivitySpoke_RouterApplianceHandWrittenUpdate1(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "tf-test-subnet%{random_suffix}" + ip_cidr_range = "10.0.0.0/28" + region = "%{region}" + network = google_compute_network.network.self_link +} + +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" + machine_type = "e2-medium" + can_ip_forward = true + zone = "%{zone}" + + boot_disk { + initialize_params { + image = "projects/debian-cloud/global/images/debian-10-buster-v20210817" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.subnetwork.name + network_ip = "10.0.0.2" + access_config { + network_tier = "PREMIUM" + } + } +} + +resource "google_compute_instance" "router-instance2" { + name = "tf-test-router-instance2%{random_suffix}" + machine_type = "e2-medium" + can_ip_forward = true + zone = "%{zone}" + + boot_disk { + initialize_params { + image = "projects/debian-cloud/global/images/debian-10-buster-v20210817" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.subnetwork.name + network_ip = "10.0.0.3" + access_config { + network_tier = "PREMIUM" + } + } +} + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-name%{random_suffix}" + location = "%{region}" + description = "An UPDATED sample spoke with two linked routher appliance instances" + labels = { + label-two = "value-two" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_router_appliance_instances { + instances { + virtual_machine = google_compute_instance.router-instance1.self_link + ip_address = "10.0.0.2" + } + instances { + virtual_machine = google_compute_instance.router-instance2.self_link + ip_address = "10.0.0.3" + } + include_import_ranges = ["ALL_IPV4_RANGES"] + site_to_site_data_transfer = true + } +} +`, context) +} + func testAccNetworkConnectivitySpoke_LinkedVPCNetworkHandWrittenLongForm(context map[string]interface{}) string { return acctest.Nprintf(` @@ -447,8 +628,8 @@ resource "google_compute_subnetwork" "subnetwork" { network = google_compute_network.network.self_link } -resource "google_compute_instance" "instance" { - name = "tf-test-instance%{random_suffix}" +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" machine_type = "e2-medium" can_ip_forward = true zone = "%{zone}" @@ -479,14 +660,14 @@ resource "google_network_connectivity_hub" "basic_hub" { resource "google_network_connectivity_spoke" "primary" { name = "tf-test-name%{random_suffix}" location = "%{region}" - description = "A sample spoke with a linked routher appliance instance" + description = "A sample spoke with a single linked routher appliance instance" labels = { label-one = "value-one" } hub = google_network_connectivity_hub.basic_hub.id linked_router_appliance_instances { instances { - virtual_machine = google_compute_instance.instance.self_link + virtual_machine = google_compute_instance.router-instance1.self_link ip_address = "10.0.0.2" } site_to_site_data_transfer = true @@ -510,8 +691,71 @@ resource "google_compute_subnetwork" "subnetwork" { network = google_compute_network.network.self_link } -resource "google_compute_instance" "instance" { - name = "tf-test-instance%{random_suffix}" +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" + machine_type = "e2-medium" + can_ip_forward = true + zone = "%{zone}" + + boot_disk { + initialize_params { + image = "projects/debian-cloud/global/images/debian-10-buster-v20210817" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.subnetwork.name + network_ip = "10.0.0.2" + access_config { + network_tier = "PREMIUM" + } + } +} + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-name%{random_suffix}" + location = "%{region}" + description = "An UPDATED sample spoke with a single linked routher appliance instance" + labels = { + label-two = "value-two" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_router_appliance_instances { + instances { + virtual_machine = google_compute_instance.router-instance1.self_link + ip_address = "10.0.0.2" + } + site_to_site_data_transfer = true + } +} +`, context) +} + +func testAccNetworkConnectivitySpoke_RouterApplianceHandWrittenUpdate1LongForm(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "tf-test-subnet%{random_suffix}" + ip_cidr_range = "10.0.0.0/28" + region = "%{region}" + network = google_compute_network.network.self_link +} + +resource "google_compute_instance" "router-instance1" { + name = "tf-test-router-instance1%{random_suffix}" machine_type = "e2-medium" can_ip_forward = true zone = "%{zone}" @@ -531,6 +775,27 @@ resource "google_compute_instance" "instance" { } } +resource "google_compute_instance" "router-instance2" { + name = "tf-test-router-instance2%{random_suffix}" + machine_type = "e2-medium" + can_ip_forward = true + zone = "%{zone}" + + boot_disk { + initialize_params { + image = "projects/debian-cloud/global/images/debian-10-buster-v20210817" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.subnetwork.name + network_ip = "10.0.0.3" + access_config { + network_tier = "PREMIUM" + } + } +} + resource "google_network_connectivity_hub" "basic_hub" { name = "tf-test-hub%{random_suffix}" description = "A sample hub" @@ -542,17 +807,309 @@ resource "google_network_connectivity_hub" "basic_hub" { resource "google_network_connectivity_spoke" "primary" { name = "tf-test-name%{random_suffix}" location = "%{region}" - description = "An UPDATED sample spoke with a linked routher appliance instance" + description = "An UPDATED sample spoke with two linked routher appliance instances" labels = { label-two = "value-two" } hub = google_network_connectivity_hub.basic_hub.id linked_router_appliance_instances { instances { - virtual_machine = google_compute_instance.instance.self_link + virtual_machine = google_compute_instance.router-instance1.self_link ip_address = "10.0.0.2" } + instances { + virtual_machine = google_compute_instance.router-instance2.self_link + ip_address = "10.0.0.3" + } + include_import_ranges = ["ALL_IPV4_RANGES"] + site_to_site_data_transfer = true + } +} +`, context) +} + +func testAccNetworkConnectivitySpoke_VPNTunnelHandWrittenHandWritten(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "tf-test-subnet%{random_suffix}" + ip_cidr_range = "10.0.0.0/28" + region = "%{region}" + network = google_compute_network.network.self_link +} + +resource "google_compute_ha_vpn_gateway" "gateway" { + name = "tf-test-gw%{random_suffix}" + network = google_compute_network.network.id +} + +resource "google_compute_external_vpn_gateway" "external_vpn_gw" { + name = "tf-test-external-gw%{random_suffix}" + redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" + description = "An externally managed VPN gateway" + interface { + id = 0 + ip_address = "8.8.8.8" + } +} + +resource "google_compute_router" "router" { + name = "tf-test-router%{random_suffix}" + region = "%{region}" + network = google_compute_network.network.name + bgp { + asn = 64514 + } +} + +resource "google_compute_vpn_tunnel" "tunnel" { + name = "tf-test-tunnel%{random_suffix}" + region = "%{region}" + vpn_gateway = google_compute_ha_vpn_gateway.gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.external_vpn_gw.id + peer_external_gateway_interface = 0 + shared_secret = "a secret message" + router = google_compute_router.router.id + vpn_gateway_interface = 0 +} + +resource "google_compute_router_interface" "router_interface" { + name = "tf-test-ri%{random_suffix}" + router = google_compute_router.router.name + region = "%{region}" + ip_range = "169.254.0.1/30" + vpn_tunnel = google_compute_vpn_tunnel.tunnel.name +} + +resource "google_compute_router_peer" "router_peer" { + name = "tf-test-peer%{random_suffix}" + router = google_compute_router.router.name + region = "%{region}" + peer_ip_address = "169.254.0.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = google_compute_router_interface.router_interface.name +} + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-name%{random_suffix}" + location = "%{region}" + description = "A sample spoke with a linked VPN Tunnel, no include_import_ranges yet" + labels = { + label-one = "value-one" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_vpn_tunnels { + uris = [google_compute_vpn_tunnel.tunnel.self_link] + site_to_site_data_transfer = true + } +} +`, context) +} + +func testAccNetworkConnectivitySpoke_VPNTunnelHandWrittenHandWrittenUpdate0(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "tf-test-subnet%{random_suffix}" + ip_cidr_range = "10.0.0.0/28" + region = "%{region}" + network = google_compute_network.network.self_link +} + +resource "google_compute_ha_vpn_gateway" "gateway" { + name = "tf-test-gw%{random_suffix}" + network = google_compute_network.network.id +} + +resource "google_compute_external_vpn_gateway" "external_vpn_gw" { + name = "tf-test-external-gw%{random_suffix}" + redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" + description = "An externally managed VPN gateway" + interface { + id = 0 + ip_address = "8.8.8.8" + } +} + +resource "google_compute_router" "router" { + name = "tf-test-router%{random_suffix}" + region = "%{region}" + network = google_compute_network.network.name + bgp { + asn = 64514 + } +} + +resource "google_compute_vpn_tunnel" "tunnel" { + name = "tf-test-tunnel%{random_suffix}" + region = "%{region}" + vpn_gateway = google_compute_ha_vpn_gateway.gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.external_vpn_gw.id + peer_external_gateway_interface = 0 + shared_secret = "a secret message" + router = google_compute_router.router.id + vpn_gateway_interface = 0 +} + +resource "google_compute_router_interface" "router_interface" { + name = "tf-test-ri%{random_suffix}" + router = google_compute_router.router.name + region = "%{region}" + ip_range = "169.254.0.1/30" + vpn_tunnel = google_compute_vpn_tunnel.tunnel.name +} + +resource "google_compute_router_peer" "router_peer" { + name = "tf-test-peer%{random_suffix}" + router = google_compute_router.router.name + region = "%{region}" + peer_ip_address = "169.254.0.2" + peer_asn = 64515 + advertised_route_priority = 100 + interface = google_compute_router_interface.router_interface.name +} + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-name%{random_suffix}" + location = "%{region}" + description = "An UPDATED sample spoke with a linked VPN Tunnel, now includes ALL_IPV4_RANGES" + labels = { + label-one = "value-one" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_vpn_tunnels { + uris = [google_compute_vpn_tunnel.tunnel.self_link] + site_to_site_data_transfer = true + include_import_ranges = ["ALL_IPV4_RANGES"] + } +} +`, context) +} + +func testAccNetworkConnectivitySpoke_InterconnectAttachmentHandWrittenHandWritten(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_router" "router" { + name = "tf-test-router%{random_suffix}" + region = "%{region}" + network = google_compute_network.network.name + bgp { + asn = 16550 + } +} + +resource "google_compute_interconnect_attachment" "interconnect_attachment" { + name = "tf-test-ia%{random_suffix}" + edge_availability_domain = "AVAILABILITY_DOMAIN_1" + type = "PARTNER" + router = google_compute_router.router.id + mtu = 1500 + region = "%{region}" +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-spoke-ia%{random_suffix}" + location = "%{region}" + description = "A sample spoke with a linked interconnect_attachment, no include_import_ranges yet" + labels = { + label-one = "value-one" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_interconnect_attachments { + uris = [google_compute_interconnect_attachment.interconnect_attachment.self_link] + site_to_site_data_transfer = true + # include_import_ranges not set initially + } +} +`, context) +} + +func testAccNetworkConnectivitySpoke_InterconnectAttachmentHandWrittenHandWrittenUpdate0(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_network_connectivity_hub" "basic_hub" { + name = "tf-test-hub%{random_suffix}" + description = "A sample hub" + labels = { + label-two = "value-one" + } +} + +resource "google_compute_network" "network" { + name = "tf-test-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_router" "router" { + name = "tf-test-router%{random_suffix}" + region = "%{region}" + network = google_compute_network.network.name + bgp { + asn = 16550 + } +} + +resource "google_compute_interconnect_attachment" "interconnect_attachment" { + name = "tf-test-ia%{random_suffix}" + edge_availability_domain = "AVAILABILITY_DOMAIN_1" + type = "PARTNER" + router = google_compute_router.router.id + mtu = 1500 + region = "%{region}" +} + +resource "google_network_connectivity_spoke" "primary" { + name = "tf-test-spoke-ia%{random_suffix}" + location = "%{region}" + description = "An updated sample spoke with interconnect_attachment, now includes ALL_IPV4_RANGES" + labels = { + label-one = "value-one" + } + hub = google_network_connectivity_hub.basic_hub.id + linked_interconnect_attachments { + uris = [google_compute_interconnect_attachment.interconnect_attachment.self_link] site_to_site_data_transfer = true + include_import_ranges = ["ALL_IPV4_RANGES"] } } `, context) diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_generated_test.go.tmpl new file mode 100644 index 000000000000..8972cd8cfef6 --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_generated_test.go.tmpl @@ -0,0 +1,183 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityInterceptDeployment_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityInterceptDeployment_basic(context), + }, + { + ResourceName: "google_network_security_intercept_deployment.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityInterceptDeployment_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_intercept_deployment.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_intercept_deployment.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityInterceptDeployment_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "tf-test-example-subnet%{random_suffix}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "tf-test-example-hc%{random_suffix}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "tf-test-example-bs%{random_suffix}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "tf-test-example-fwr%{random_suffix}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" +} + +resource "google_network_security_intercept_deployment_group" "deployment_group" { + provider = google-beta + intercept_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_intercept_deployment" "default" { + provider = google-beta + intercept_deployment_id = "tf-test-example-deployment%{random_suffix}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + intercept_deployment_group = google_network_security_intercept_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityInterceptDeployment_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "tf-test-example-subnet%{random_suffix}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "tf-test-example-hc%{random_suffix}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "tf-test-example-bs%{random_suffix}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "tf-test-example-fwr%{random_suffix}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" +} + +resource "google_network_security_intercept_deployment_group" "deployment_group" { + provider = google-beta + intercept_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_intercept_deployment" "default" { + provider = google-beta + intercept_deployment_id = "tf-test-example-deployment%{random_suffix}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + intercept_deployment_group = google_network_security_intercept_deployment_group.deployment_group.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_group_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_group_generated_test.go.tmpl new file mode 100644 index 000000000000..b8b261051f1b --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_intercept_deployment_group_generated_test.go.tmpl @@ -0,0 +1,91 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityInterceptDeploymentGroup_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityInterceptDeploymentGroup_basic(context), + }, + { + ResourceName: "google_network_security_intercept_deployment_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityInterceptDeploymentGroup_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_intercept_deployment_group.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_intercept_deployment_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityInterceptDeploymentGroup_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_intercept_deployment_group" "default" { + provider = google-beta + intercept_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityInterceptDeploymentGroup_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_intercept_deployment_group" "default" { + provider = google-beta + intercept_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_generated_test.go.tmpl new file mode 100644 index 000000000000..2416e75513e3 --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_generated_test.go.tmpl @@ -0,0 +1,185 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityMirroringDeployment_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityMirroringDeployment_basic(context), + }, + { + ResourceName: "google_network_security_mirroring_deployment.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityMirroringDeployment_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_mirroring_deployment.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_mirroring_deployment.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityMirroringDeployment_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "tf-test-example-subnet%{random_suffix}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "tf-test-example-hc%{random_suffix}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "tf-test-example-bs%{random_suffix}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "tf-test-example-fwr%{random_suffix}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" + is_mirroring_collector = true +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_deployment" "default" { + provider = google-beta + mirroring_deployment_id = "tf-test-example-deployment%{random_suffix}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityMirroringDeployment_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + provider = google-beta + name = "tf-test-example-subnet%{random_suffix}" + region = "us-central1" + ip_cidr_range = "10.1.0.0/16" + network = google_compute_network.network.name +} + +resource "google_compute_region_health_check" "health_check" { + provider = google-beta + name = "tf-test-example-hc%{random_suffix}" + region = "us-central1" + http_health_check { + port = 80 + } +} + +resource "google_compute_region_backend_service" "backend_service" { + provider = google-beta + name = "tf-test-example-bs%{random_suffix}" + region = "us-central1" + health_checks = [google_compute_region_health_check.health_check.id] + protocol = "UDP" + load_balancing_scheme = "INTERNAL" +} + +resource "google_compute_forwarding_rule" "forwarding_rule" { + provider = google-beta + name = "tf-test-example-fwr%{random_suffix}" + region = "us-central1" + network = google_compute_network.network.name + subnetwork = google_compute_subnetwork.subnetwork.name + backend_service = google_compute_region_backend_service.backend_service.id + load_balancing_scheme = "INTERNAL" + ports = [6081] + ip_protocol = "UDP" + is_mirroring_collector = true +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_deployment" "default" { + provider = google-beta + mirroring_deployment_id = "tf-test-example-deployment%{random_suffix}" + location = "us-central1-a" + forwarding_rule = google_compute_forwarding_rule.forwarding_rule.id + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_group_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_group_generated_test.go.tmpl new file mode 100644 index 000000000000..6cd863756551 --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_deployment_group_generated_test.go.tmpl @@ -0,0 +1,91 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityMirroringDeploymentGroup_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityMirroringDeploymentGroup_basic(context), + }, + { + ResourceName: "google_network_security_mirroring_deployment_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityMirroringDeploymentGroup_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_mirroring_deployment_group.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_mirroring_deployment_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityMirroringDeploymentGroup_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "default" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityMirroringDeploymentGroup_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "default" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_association_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_association_generated_test.go.tmpl new file mode 100644 index 000000000000..2639b2c142a1 --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_association_generated_test.go.tmpl @@ -0,0 +1,133 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityMirroringEndpointGroupAssociation_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityMirroringEndpointGroupAssociation_basic(context), + }, + { + ResourceName: "google_network_security_mirroring_endpoint_group_association.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityMirroringEndpointGroupAssociation_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_mirroring_endpoint_group_association.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_mirroring_endpoint_group_association.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityMirroringEndpointGroupAssociation_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "producer_network" { + provider = google-beta + name = "tf-test-example-prod-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_network" "consumer_network" { + provider = google-beta + name = "tf-test-example-cons-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.producer_network.id +} + +resource "google_network_security_mirroring_endpoint_group" "endpoint_group" { + provider = google-beta + mirroring_endpoint_group_id = "tf-test-example-eg%{random_suffix}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id +} + +resource "google_network_security_mirroring_endpoint_group_association" "default" { + provider = google-beta + mirroring_endpoint_group_association_id = "tf-test-example-ega%{random_suffix}" + location = "global" + network = google_compute_network.consumer_network.id + mirroring_endpoint_group = google_network_security_mirroring_endpoint_group.endpoint_group.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityMirroringEndpointGroupAssociation_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "producer_network" { + provider = google-beta + name = "tf-test-example-prod-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_network" "consumer_network" { + provider = google-beta + name = "tf-test-example-cons-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.producer_network.id +} + +resource "google_network_security_mirroring_endpoint_group" "endpoint_group" { + provider = google-beta + mirroring_endpoint_group_id = "tf-test-example-eg%{random_suffix}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id +} + +resource "google_network_security_mirroring_endpoint_group_association" "default" { + provider = google-beta + mirroring_endpoint_group_association_id = "tf-test-example-ega%{random_suffix}" + location = "global" + network = google_compute_network.consumer_network.id + mirroring_endpoint_group = google_network_security_mirroring_endpoint_group.endpoint_group.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_generated_test.go.tmpl b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_generated_test.go.tmpl new file mode 100644 index 000000000000..04495905941c --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_security_mirroring_endpoint_group_generated_test.go.tmpl @@ -0,0 +1,105 @@ +package networksecurity_test +{{- if ne $.TargetVersionName "ga" }} + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetworkSecurityMirroringEndpointGroup_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityMirroringEndpointGroup_basic(context), + }, + { + ResourceName: "google_network_security_mirroring_endpoint_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + }, + { + Config: testAccNetworkSecurityMirroringEndpointGroup_update(context), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_network_security_mirroring_endpoint_group.default", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_network_security_mirroring_endpoint_group.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"update_time", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityMirroringEndpointGroup_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_endpoint_group" "default" { + provider = google-beta + mirroring_endpoint_group_id = "tf-test-example-eg%{random_suffix}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "bar" + } +} +`, context) +} + +func testAccNetworkSecurityMirroringEndpointGroup_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "network" { + provider = google-beta + name = "tf-test-example-network%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_network_security_mirroring_deployment_group" "deployment_group" { + provider = google-beta + mirroring_deployment_group_id = "tf-test-example-dg%{random_suffix}" + location = "global" + network = google_compute_network.network.id +} + +resource "google_network_security_mirroring_endpoint_group" "default" { + provider = google-beta + mirroring_endpoint_group_id = "tf-test-example-eg%{random_suffix}" + location = "global" + mirroring_deployment_group = google_network_security_mirroring_deployment_group.deployment_group.id + labels = { + foo = "goo" + } +} +`, context) +} + +{{ end }} diff --git a/mmv1/third_party/terraform/services/networksecurity/resource_network_services_authz_policy_test.go b/mmv1/third_party/terraform/services/networksecurity/resource_network_services_authz_policy_test.go new file mode 100644 index 000000000000..1315963ffb44 --- /dev/null +++ b/mmv1/third_party/terraform/services/networksecurity/resource_network_services_authz_policy_test.go @@ -0,0 +1,365 @@ +package networksecurity_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccNetworkSecurityAuthzPolicy_networkServicesAuthzPolicyHttpRules(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project": envvar.GetTestProjectFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkSecurityAuthzPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkSecurityAuthzPolicy_networkServicesAuthzPolicyHttpRules(context), + }, + { + ResourceName: "google_network_security_authz_policy.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "location", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkSecurityAuthzPolicy_networkServicesAuthzPolicyHttpRules(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "default" { + name = "lb-network-%{random_suffix}" + project = "%{project}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "backend-subnet-%{random_suffix}" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.1.2.0/24" + network = google_compute_network.default.id +} + +resource "google_compute_subnetwork" "proxy_only" { + name = "proxy-only-subnet-%{random_suffix}" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.129.0.0/23" + purpose = "REGIONAL_MANAGED_PROXY" + role = "ACTIVE" + network = google_compute_network.default.id +} + +resource "google_compute_address" "default" { + name = "l7-ilb-ip-address-%{random_suffix}" + project = "%{project}" + region = "us-west1" + subnetwork = google_compute_subnetwork.default.id + address_type = "INTERNAL" + purpose = "GCE_ENDPOINT" +} + +resource "google_compute_region_health_check" "default" { + name = "l7-ilb-basic-check-%{random_suffix}" + project = "%{project}" + region = "us-west1" + + http_health_check { + port_specification = "USE_SERVING_PORT" + } +} + +resource "google_compute_region_backend_service" "url_map" { + name = "l7-ilb-backend-service-%{random_suffix}" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + + health_checks = [google_compute_region_health_check.default.id] +} + +resource "google_compute_region_url_map" "default" { + name = "l7-ilb-map-%{random_suffix}" + project = "%{project}" + region = "us-west1" + default_service = google_compute_region_backend_service.url_map.id +} + +resource "google_compute_region_target_http_proxy" "default" { + name = "l7-ilb-proxy-%{random_suffix}" + project = "%{project}" + region = "us-west1" + url_map = google_compute_region_url_map.default.id +} + +resource "google_compute_forwarding_rule" "default" { + name = "l7-ilb-forwarding-rule-%{random_suffix}" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + ip_protocol = "TCP" + port_range = "80" + target = google_compute_region_target_http_proxy.default.id + ip_address = google_compute_address.default.id + + depends_on = [google_compute_subnetwork.proxy_only] +} + +resource "google_compute_region_backend_service" "authz_extension" { + name = "authz-service-%{random_suffix}" + project = "%{project}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_network_services_authz_extension" "default" { + name = "my-authz-ext-%{random_suffix}" + project = "%{project}" + location = "us-west1" + + description = "my description" + load_balancing_scheme = "INTERNAL_MANAGED" + authority = "ext11.com" + service = google_compute_region_backend_service.authz_extension.self_link + timeout = "0.1s" + fail_open = false + forward_headers = ["Authorization"] +} + +resource "google_network_security_authz_policy" "default" { + name = "tf-test-my-authz-policy-%{random_suffix}" + project = "%{project}" + location = "us-west1" + description = "my description" + + target { + load_balancing_scheme = "INTERNAL_MANAGED" + resources = [ google_compute_forwarding_rule.default.self_link ] + } + + action = "CUSTOM" + custom_provider { + authz_extension { + resources = [ google_network_services_authz_extension.default.id ] + } + } + + http_rules { + from { + not_sources { + # Prefix + principals { + ignore_case = false + prefix = "prefix" + } + resources { + iam_service_account { + ignore_case = false + prefix = "prefix" + } + tag_value_id_set { + ids = ["1"] + } + } + # Suffix / Ignore case + principals { + ignore_case = true + suffix = "suffix" + } + resources { + iam_service_account { + ignore_case = true + suffix = "suffix" + } + tag_value_id_set { + ids = ["2"] + } + } + # Exact + principals { + ignore_case = true + exact = "exact" + } + resources { + iam_service_account { + ignore_case = true + exact = "exact" + } + tag_value_id_set { + ids = ["3"] + } + } + # Contains / Ignore case + principals { + ignore_case = true + contains = "contains" + } + resources { + iam_service_account { + ignore_case = true + contains = "contains" + } + tag_value_id_set { + ids = ["4"] + } + } + } + sources { + # Prefix + principals { + ignore_case = false + prefix = "prefix" + } + resources { + iam_service_account { + ignore_case = false + prefix = "prefix" + } + tag_value_id_set { + ids = ["1"] + } + } + # Suffix / Ignore case + principals { + ignore_case = true + suffix = "suffix" + } + resources { + iam_service_account { + ignore_case = true + suffix = "suffix" + } + tag_value_id_set { + ids = ["2"] + } + } + # Exact + principals { + exact = "exact" + ignore_case = false + } + resources { + iam_service_account { + exact = "exact" + ignore_case = false + } + tag_value_id_set { + ids = ["3"] + } + } + # Contains / Ignore case + principals { + contains = "contains" + ignore_case = true + } + resources { + iam_service_account { + contains = "contains" + ignore_case = true + } + tag_value_id_set { + ids = ["4"] + } + } + } + } + to { + operations { + methods = ["GET", "PUT", "POST", "HEAD", "PATCH", "DELETE", "OPTIONS"] + header_set { + # Prefix + headers { + name = "PrefixHeader" + value { + ignore_case = false + prefix = "prefix" + } + } + # Suffix / Ignore case + headers { + name = "SuffixHeader" + value { + ignore_case = true + suffix = "suffix" + } + } + # Exact + headers { + name = "ExactHeader" + value { + exact = "exact" + ignore_case = false + } + } + # Contains / Ignore case + headers { + name = "ContainsHeader" + value { + contains = "contains" + ignore_case = true + } + } + } + # Prefix + hosts { + ignore_case = false + prefix = "prefix" + } + paths { + ignore_case = false + prefix = "prefix" + } + # Suffix / Ignore case + hosts { + ignore_case = true + suffix = "suffix" + } + paths { + ignore_case = true + suffix = "suffix" + } + # Exact + hosts { + exact = "exact" + ignore_case = false + } + paths { + exact = "exact" + ignore_case = false + } + # Contains / Ignore case + hosts { + contains = "contains" + ignore_case = true + } + paths { + contains = "contains" + ignore_case = true + } + } + } + when = "request.host.endsWith('.example.com')" + } + + labels = { + foo = "bar" + } +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/networkservices/resource_network_services_authz_extension_test.go b/mmv1/third_party/terraform/services/networkservices/resource_network_services_authz_extension_test.go new file mode 100644 index 000000000000..9a6a192f21c5 --- /dev/null +++ b/mmv1/third_party/terraform/services/networkservices/resource_network_services_authz_extension_test.go @@ -0,0 +1,293 @@ +package networkservices_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccNetworkServicesAuthzExtension_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project": envvar.GetTestProjectFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkServicesAuthzExtensionDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkServicesAuthzExtension_start(context), + }, + { + ResourceName: "google_network_services_authz_extension.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "location", "service", "terraform_labels"}, + }, + { + Config: testAccNetworkServicesAuthzExtension_update(context), + }, + { + ResourceName: "google_network_services_authz_extension.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"labels", "location", "service", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetworkServicesAuthzExtension_start(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "default" { + name = "lb-network" + project = "%{project}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "backend-subnet" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.1.2.0/24" + network = google_compute_network.default.id +} + +resource "google_compute_subnetwork" "proxy_only" { + name = "proxy-only-subnet" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.129.0.0/23" + purpose = "REGIONAL_MANAGED_PROXY" + role = "ACTIVE" + network = google_compute_network.default.id +} + +resource "google_compute_address" "default" { + name = "l7-ilb-ip-address" + project = "%{project}" + region = "us-west1" + subnetwork = google_compute_subnetwork.default.id + address_type = "INTERNAL" + purpose = "GCE_ENDPOINT" +} + + +resource "google_compute_region_health_check" "default" { + name = "l7-ilb-basic-check" + project = "%{project}" + region = "us-west1" + + http_health_check { + port_specification = "USE_SERVING_PORT" + } +} + +resource "google_compute_region_backend_service" "url_map" { + name = "l7-ilb-backend-service" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + + health_checks = [google_compute_region_health_check.default.id] +} + +resource "google_compute_forwarding_rule" "default" { + name = "l7-ilb-forwarding-rule" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + ip_protocol = "TCP" + port_range = "80" + target = google_compute_region_target_http_proxy.default.id + ip_address = google_compute_address.default.id + + depends_on = [google_compute_subnetwork.proxy_only] +} + +resource "google_compute_region_url_map" "default" { + name = "l7-ilb-map" + project = "%{project}" + region = "us-west1" + default_service = google_compute_region_backend_service.url_map.id +} + +resource "google_compute_region_target_http_proxy" "default" { + name = "l7-ilb-proxy" + project = "%{project}" + region = "us-west1" + url_map = google_compute_region_url_map.default.id +} + +resource "google_compute_region_backend_service" "default" { + name = "authz-service" + project = "%{project}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_compute_region_backend_service" "updated" { + name = "authz-service-updated" + project = "%{project}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_network_services_authz_extension" "default" { + name = "tf-test-my-authz-ext%{random_suffix}" + project = "%{project}" + location = "us-west1" + + description = "my description" + load_balancing_scheme = "INTERNAL_MANAGED" + authority = "ext11.com" + service = google_compute_region_backend_service.default.self_link + timeout = "0.1s" + fail_open = false + forward_headers = ["Authorization"] +} +`, context) +} + +func testAccNetworkServicesAuthzExtension_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "default" { + name = "lb-network" + project = "%{project}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "default" { + name = "backend-subnet" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.1.2.0/24" + network = google_compute_network.default.id +} + +resource "google_compute_subnetwork" "proxy_only" { + name = "proxy-only-subnet" + project = "%{project}" + region = "us-west1" + ip_cidr_range = "10.129.0.0/23" + purpose = "REGIONAL_MANAGED_PROXY" + role = "ACTIVE" + network = google_compute_network.default.id +} + +resource "google_compute_address" "default" { + name = "l7-ilb-ip-address" + project = "%{project}" + region = "us-west1" + subnetwork = google_compute_subnetwork.default.id + address_type = "INTERNAL" + purpose = "GCE_ENDPOINT" +} + +resource "google_compute_region_health_check" "default" { + name = "l7-ilb-basic-check" + project = "%{project}" + region = "us-west1" + + http_health_check { + port_specification = "USE_SERVING_PORT" + } +} + +resource "google_compute_region_backend_service" "url_map" { + name = "l7-ilb-backend-service" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + + health_checks = [google_compute_region_health_check.default.id] +} + +resource "google_compute_forwarding_rule" "default" { + name = "l7-ilb-forwarding-rule" + project = "%{project}" + region = "us-west1" + load_balancing_scheme = "INTERNAL_MANAGED" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + ip_protocol = "TCP" + port_range = "80" + target = google_compute_region_target_http_proxy.default.id + ip_address = google_compute_address.default.id + + depends_on = [google_compute_subnetwork.proxy_only] +} + +resource "google_compute_region_url_map" "default" { + name = "l7-ilb-map" + project = "%{project}" + region = "us-west1" + default_service = google_compute_region_backend_service.url_map.id +} + +resource "google_compute_region_target_http_proxy" "default" { + name = "l7-ilb-proxy" + project = "%{project}" + region = "us-west1" + url_map = google_compute_region_url_map.default.id +} + +resource "google_compute_region_backend_service" "default" { + name = "authz-service" + project = "%{project}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_compute_region_backend_service" "updated" { + name = "authz-service-updated" + project = "%{project}" + region = "us-west1" + + protocol = "HTTP2" + load_balancing_scheme = "INTERNAL_MANAGED" + port_name = "grpc" +} + +resource "google_network_services_authz_extension" "default" { + name = "tf-test-my-authz-ext%{random_suffix}" + project = "%{project}" + location = "us-west1" + + description = "updated description" + load_balancing_scheme = "INTERNAL_MANAGED" + authority = "ext11.com" + service = google_compute_region_backend_service.updated.self_link + timeout = "0.1s" + fail_open = false + forward_headers = ["Authorization"] + wire_format = "EXT_PROC_GRPC" + + metadata = { + forwarding_rule_id = google_compute_forwarding_rule.default.id + } + + labels = { + foo = "bar" + } +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructure_test.go b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructure_test.go index ac0f3cdb3143..af95923d4a8d 100644 --- a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructure_test.go +++ b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructure_test.go @@ -21,7 +21,7 @@ func TestAccOracleDatabaseCloudExadataInfrastructure_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "gcp_oracle_zone"), resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "properties.#"), resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "properties.0.compute_count"), - resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "display_name", "ofake-exadata-for-vm display name"), + resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "display_name", "ofake-do-not-delete-tf-exadata display name"), resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "gcp_oracle_zone", "us-east4-b-r1"), resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "properties.0.state", "AVAILABLE"), resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructure.my-exadata", "properties.0.shape", "Exadata.X9M"), diff --git a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructures_test.go b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructures_test.go index 9625a4907e83..46c1b272d08d 100644 --- a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructures_test.go +++ b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_cloud_exadata_infrastructures_test.go @@ -25,7 +25,6 @@ func TestAccOracleDatabaseCloudExadataInfrastructures_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructures.my_cloud_exadatas", "cloud_exadata_infrastructures.0.properties.0.cpu_count"), resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructures.my_cloud_exadatas", "cloud_exadata_infrastructures.0.properties.0.compute_count"), resource.TestCheckResourceAttrSet("data.google_oracle_database_cloud_exadata_infrastructures.my_cloud_exadatas", "cloud_exadata_infrastructures.0.properties.0.max_cpu_count"), - resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructures.my_cloud_exadatas", "cloud_exadata_infrastructures.0.properties.0.state", "AVAILABLE"), resource.TestCheckResourceAttr("data.google_oracle_database_cloud_exadata_infrastructures.my_cloud_exadatas", "cloud_exadata_infrastructures.0.properties.0.max_cpu_count", "252"), ), }, diff --git a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_db_servers_test.go b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_db_servers_test.go index 04e265c7ff48..fc91c97ef3b1 100644 --- a/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_db_servers_test.go +++ b/mmv1/third_party/terraform/services/oracledatabase/data_source_oracle_database_db_servers_test.go @@ -22,8 +22,6 @@ func TestAccOracleDatabaseDbServers_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.google_oracle_database_db_servers.my_db_servers", "db_servers.1.display_name"), resource.TestCheckResourceAttrSet("data.google_oracle_database_db_servers.my_db_servers", "db_servers.1.properties.#"), resource.TestCheckResourceAttrSet("data.google_oracle_database_db_servers.my_db_servers", "db_servers.1.properties.0.max_ocpu_count"), - resource.TestCheckResourceAttr("data.google_oracle_database_db_servers.my_db_servers", "db_servers.0.display_name", "dbServer-1"), - resource.TestCheckResourceAttr("data.google_oracle_database_db_servers.my_db_servers", "db_servers.1.display_name", "dbServer-2"), resource.TestCheckResourceAttr("data.google_oracle_database_db_servers.my_db_servers", "db_servers.0.properties.0.max_ocpu_count", "126"), resource.TestCheckResourceAttr("data.google_oracle_database_db_servers.my_db_servers", "db_servers.1.properties.0.max_ocpu_count", "126"), ), diff --git a/mmv1/third_party/terraform/services/orgpolicy/resource_org_policy_policy_test.go b/mmv1/third_party/terraform/services/orgpolicy/resource_org_policy_policy_test.go index f4cb03f24fde..3d44bbb3fc7c 100644 --- a/mmv1/third_party/terraform/services/orgpolicy/resource_org_policy_policy_test.go +++ b/mmv1/third_party/terraform/services/orgpolicy/resource_org_policy_policy_test.go @@ -458,3 +458,106 @@ func testAccCheckOrgPolicyPolicyDestroyProducer(t *testing.T) func(s *terraform. return nil } } +func TestAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(t *testing.T) { + // Skip this test as no constraints yet launched in production, verified functionality with manual testing. + t.Skip() + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckOrgPolicyPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(context), + }, + { + ResourceName: "google_org_policy_policy.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "spec.0.rules.0.condition.0.expression"}, + }, + }, + }) +} +func testAccOrgPolicyPolicy_EnforceParameterizedMCPolicy(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_org_policy_policy" "primary" { + name = "projects/${google_project.basic.name}/policies/essentialcontacts.managed.allowedContactDomains" + parent = "projects/${google_project.basic.name}" + + spec { + rules { + enforce = "TRUE" + parameters = "{\"allowedDomains\": [\"@google.com\"]}" + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-id%{random_suffix}" + name = "tf-test-id%{random_suffix}" + org_id = "%{org_id}" + deletion_policy = "DELETE" +} + + +`, context) +} + +func TestAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(t *testing.T) { + // Skip this test as no constraints yet launched in production, verified functionality with manual testing. + t.Skip() + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckOrgPolicyPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(context), + }, + { + ResourceName: "google_org_policy_policy.primary", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "spec.0.rules.0.condition.0.expression"}, + }, + }, + }) +} +func testAccOrgPolicyPolicy_EnforceParameterizedMCDryRunPolicy(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_org_policy_policy" "primary" { + name = "projects/${google_project.basic.name}/policies/essentialcontacts.managed.allowedContactDomains" + parent = "projects/${google_project.basic.name}" + + dry_run_spec { + rules { + enforce = "TRUE" + parameters = "{\"allowedDomains\": [\"@google.com\"]}" + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-id%{random_suffix}" + name = "tf-test-id%{random_suffix}" + org_id = "%{org_id}" + deletion_policy = "DELETE" +} + + +`, context) +} diff --git a/mmv1/third_party/terraform/services/osconfig/resource_os_config_os_policy_assignment_meta.yaml b/mmv1/third_party/terraform/services/osconfig/resource_os_config_os_policy_assignment_meta.yaml new file mode 100644 index 000000000000..f6aaabc69d89 --- /dev/null +++ b/mmv1/third_party/terraform/services/osconfig/resource_os_config_os_policy_assignment_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_os_config_os_policy_assignment' +generation_type: 'handwritten' +api_service_name: 'osconfig.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'OsPolicyAssignment' diff --git a/mmv1/third_party/terraform/services/privateca/resource_privateca_certificate_authority_test.go b/mmv1/third_party/terraform/services/privateca/resource_privateca_certificate_authority_test.go index 03bab0a9d7db..fac616afad3a 100644 --- a/mmv1/third_party/terraform/services/privateca/resource_privateca_certificate_authority_test.go +++ b/mmv1/third_party/terraform/services/privateca/resource_privateca_certificate_authority_test.go @@ -126,9 +126,10 @@ func TestAccPrivatecaCertificateAuthority_subordinateCaActivatedByFirstPartyIssu random_suffix := acctest.RandString(t, 10) context := map[string]interface{}{ - "root_location": "us-central1", - "sub_location": "australia-southeast1", - "random_suffix": random_suffix, + "root_location": "us-central1", + "sub_location": "australia-southeast1", + "random_suffix": random_suffix, + "first_label_value": "bar", } resourceName := "google_privateca_certificate_authority.sub-1" @@ -174,6 +175,47 @@ func TestAccPrivatecaCertificateAuthority_subordinateCaActivatedByFirstPartyIssu }) } +func TestAccPrivatecaCertificateAuthority_subordinateCaCanUpdateLabel(t *testing.T) { + t.Parallel() + acctest.SkipIfVcr(t) + + random_suffix := acctest.RandString(t, 10) + context1 := map[string]interface{}{ + "root_location": "us-central1", + "sub_location": "australia-southeast1", + "random_suffix": random_suffix, + "first_label_value": "bar-1", + } + + context2 := map[string]interface{}{ + "root_location": "us-central1", + "sub_location": "australia-southeast1", + "random_suffix": random_suffix, + "first_label_value": "bar-2", + } + + resourceName := "google_privateca_certificate_authority.sub-1" + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckPrivatecaCertificateAuthorityDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccPrivatecaCertificateAuthority_privatecaCertificateAuthoritySubordinateWithFirstPartyIssuer(context1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "labels.first_label", context1["first_label_value"].(string)), + ), + }, + { + Config: testAccPrivatecaCertificateAuthority_privatecaCertificateAuthoritySubordinateWithFirstPartyIssuer(context2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "labels.first_label", context2["first_label_value"].(string)), + ), + }, + }, + }) +} + func testAccPrivatecaCertificateAuthority_privatecaCertificateAuthorityBasicRoot(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_privateca_certificate_authority" "default" { @@ -468,6 +510,10 @@ resource "google_privateca_certificate_authority" "sub-1" { } type = "SUBORDINATE" + labels = { + first_label = "%{first_label_value}" + } + // Disable CA deletion related safe checks for easier cleanup. deletion_protection = false skip_grace_period = true diff --git a/mmv1/third_party/terraform/services/recaptcha/resource_recaptcha_enterprise_key_meta.yaml.tmpl b/mmv1/third_party/terraform/services/recaptchaenterprise/resource_recaptcha_enterprise_key_meta.yaml.tmpl similarity index 100% rename from mmv1/third_party/terraform/services/recaptcha/resource_recaptcha_enterprise_key_meta.yaml.tmpl rename to mmv1/third_party/terraform/services/recaptchaenterprise/resource_recaptcha_enterprise_key_meta.yaml.tmpl diff --git a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_config.go b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_config.go index 4d4aae711fd0..e1d31ccc75a3 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_config.go +++ b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_config.go @@ -8,15 +8,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. var ( _ datasource.DataSource = &GoogleClientConfigDataSource{} _ datasource.DataSourceWithConfigure = &GoogleClientConfigDataSource{} - _ fwresource.LocationDescriber = &GoogleClientConfigModel{} ) func NewGoogleClientConfigDataSource() datasource.DataSource { @@ -24,7 +22,7 @@ func NewGoogleClientConfigDataSource() datasource.DataSource { } type GoogleClientConfigDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } type GoogleClientConfigModel struct { @@ -38,17 +36,6 @@ type GoogleClientConfigModel struct { DefaultLabels types.Map `tfsdk:"default_labels"` } -func (m *GoogleClientConfigModel) GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) fwresource.LocationDescription { - return fwresource.LocationDescription{ - RegionSchemaField: types.StringValue("region"), - ZoneSchemaField: types.StringValue("zone"), - ResourceRegion: m.Region, - ResourceZone: m.Zone, - ProviderRegion: providerConfig.Region, - ProviderZone: providerConfig.Zone, - } -} - func (d *GoogleClientConfigDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_client_config" } @@ -102,11 +89,11 @@ func (d *GoogleClientConfigDataSource) Configure(ctx context.Context, req dataso return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -131,15 +118,25 @@ func (d *GoogleClientConfigDataSource) Read(ctx context.Context, req datasource. return } - locationInfo := data.GetLocationDescription(d.providerConfig) - region, _ := locationInfo.GetRegion() - zone, _ := locationInfo.GetZone() + data.Id = types.StringValue(fmt.Sprintf("projects/%s/regions/%s/zones/%s", d.providerConfig.Project, d.providerConfig.Region, d.providerConfig.Zone)) + data.Project = types.StringValue(d.providerConfig.Project) + data.Region = types.StringValue(d.providerConfig.Region) + data.Zone = types.StringValue(d.providerConfig.Zone) + + // Convert default labels from SDK type system to plugin-framework data type + m := map[string]*string{} + for k, v := range d.providerConfig.DefaultLabels { + // m[k] = types.StringValue(v) + val := v + m[k] = &val + } + dls, diags := types.MapValueFrom(ctx, types.StringType, m) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } - data.Id = types.StringValue(fmt.Sprintf("projects/%s/regions/%s/zones/%s", d.providerConfig.Project.String(), region.String(), zone.String())) - data.Project = d.providerConfig.Project - data.Region = region - data.Zone = zone - data.DefaultLabels = d.providerConfig.DefaultLabels + data.DefaultLabels = dls token, err := d.providerConfig.TokenSource.Token() if err != nil { diff --git a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_openid_userinfo.go b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_openid_userinfo.go index 18dcf080c04a..df809e557624 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_openid_userinfo.go +++ b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_client_openid_userinfo.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. @@ -23,7 +24,7 @@ func NewGoogleClientOpenIDUserinfoDataSource() datasource.DataSource { } type GoogleClientOpenIDUserinfoDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } type GoogleClientOpenIDUserinfoModel struct { @@ -68,11 +69,11 @@ func (d *GoogleClientOpenIDUserinfoDataSource) Configure(ctx context.Context, re return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -99,8 +100,11 @@ func (d *GoogleClientOpenIDUserinfoDataSource) Read(ctx context.Context, req dat } userAgent := fwtransport.GenerateFrameworkUserAgentString(metaData, d.providerConfig.UserAgent) - email := fwtransport.GetCurrentUserEmailFramework(d.providerConfig, userAgent, &diags) - + email, err := transport_tpg.GetCurrentUserEmail(d.providerConfig, userAgent) + if err != nil { + diags.AddError("error retrieving userinfo for your provider credentials", err.Error()) + return + } data.Email = types.StringValue(email) data.Id = types.StringValue(email) diff --git a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_service_account_id_token.go b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_service_account_id_token.go index efbd3f46d0f2..14fb361b70f7 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_service_account_id_token.go +++ b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_service_account_id_token.go @@ -74,7 +74,7 @@ func dataSourceGoogleServiceAccountIdTokenRead(d *schema.ResourceData, meta inte targetAudience := d.Get("target_audience").(string) creds, err := config.GetCredentials([]string{userInfoScope}, false) if err != nil { - return fmt.Errorf("error calling getCredentials(): %v", err) + return fmt.Errorf("error calling GetCredentials(): %v", err) } targetServiceAccount := d.Get("target_service_account").(string) diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token.go new file mode 100644 index 000000000000..de98a6c0ef06 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token.go @@ -0,0 +1,152 @@ +package resourcemanager + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" + "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-google/google/fwutils" + "github.com/hashicorp/terraform-provider-google/google/fwvalidators" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "google.golang.org/api/iamcredentials/v1" +) + +var _ ephemeral.EphemeralResource = &googleEphemeralServiceAccountAccessToken{} + +func GoogleEphemeralServiceAccountAccessToken() ephemeral.EphemeralResource { + return &googleEphemeralServiceAccountAccessToken{} +} + +type googleEphemeralServiceAccountAccessToken struct { + providerConfig *transport_tpg.Config +} + +func (p *googleEphemeralServiceAccountAccessToken) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_service_account_access_token" +} + +type ephemeralServiceAccountAccessTokenModel struct { + TargetServiceAccount types.String `tfsdk:"target_service_account"` + AccessToken types.String `tfsdk:"access_token"` + Scopes types.Set `tfsdk:"scopes"` + Delegates types.Set `tfsdk:"delegates"` + Lifetime types.String `tfsdk:"lifetime"` +} + +func (p *googleEphemeralServiceAccountAccessToken) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) { + resp.Schema.Description = "This ephemeral resource provides a google oauth2 access_token for a different service account than the one initially running the script." + resp.Schema.MarkdownDescription = "This ephemeral resource provides a google oauth2 access_token for a different service account than the one initially running the script." + + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "target_service_account": schema.StringAttribute{ + Description: "The service account to impersonate (e.g. `service_B@your-project-id.iam.gserviceaccount.com`)", + Required: true, + Validators: []validator.String{ + fwvalidators.ServiceAccountEmailValidator{}, + }, + }, + "access_token": schema.StringAttribute{ + Description: "The `access_token` representing the new generated identity.", + Sensitive: true, + Computed: true, + }, + "lifetime": schema.StringAttribute{ + Description: "Lifetime of the impersonated token (defaults to its max: `3600s`)", + Optional: true, + Computed: true, + Validators: []validator.String{ + fwvalidators.BoundedDuration{ + MinDuration: 0, + MaxDuration: 3600 * time.Second, + }, + }, + }, + "scopes": schema.SetAttribute{ + Description: "The scopes the new credential should have (e.g. `['cloud-platform']`)", + Required: true, + ElementType: types.StringType, + }, + "delegates": schema.SetAttribute{ + Description: "Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. (e.g. `['projects/-/serviceAccounts/delegate-svc-account@project-id.iam.gserviceaccount.com']`)", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.ValueStringsAre(fwvalidators.ServiceAccountEmailValidator{}), + }, + }, + }, + } +} + +func (p *googleEphemeralServiceAccountAccessToken) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + pd, ok := req.ProviderData.(*transport_tpg.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + // Required for accessing userAgent and passing as an argument into a util function + p.providerConfig = pd +} + +func (p *googleEphemeralServiceAccountAccessToken) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) { + var data ephemeralServiceAccountAccessTokenModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + // This is the default value for the lifetime of the access token + // Both ephemeral resources and data sources do not allow you to set a value for this attribute in the schema + if data.Lifetime.IsNull() { + data.Lifetime = types.StringValue("3600s") + } + + service := p.providerConfig.NewIamCredentialsClient(p.providerConfig.UserAgent) + name := fmt.Sprintf("projects/-/serviceAccounts/%s", data.TargetServiceAccount.ValueString()) + + ScopesSetValue, diags := data.Scopes.ToSetValue(ctx) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + var delegates []string + if !data.Delegates.IsNull() { + delegates = fwutils.StringSet(data.Delegates) + } + + tokenRequest := &iamcredentials.GenerateAccessTokenRequest{ + Lifetime: data.Lifetime.ValueString(), + Delegates: delegates, + Scope: tpgresource.CanonicalizeServiceScopes(fwutils.StringSet(ScopesSetValue)), + } + + at, err := service.Projects.ServiceAccounts.GenerateAccessToken(name, tokenRequest).Do() + if err != nil { + resp.Diagnostics.AddError( + "Error generating access token", + fmt.Sprintf("Error generating access token: %s", err), + ) + return + } + + data.AccessToken = types.StringValue(at.AccessToken) + resp.Diagnostics.Append(resp.Result.Set(ctx, data)...) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token_test.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token_test.go new file mode 100644 index 000000000000..27ffe2af58b8 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_access_token_test.go @@ -0,0 +1,109 @@ +package resourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccEphemeralServiceAccountToken_basic(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "basic", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountToken_basic(targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountToken_withDelegates(t *testing.T) { + t.Parallel() + + project := envvar.GetTestProjectFromEnv() + initialServiceAccount := envvar.GetTestServiceAccountFromEnv(t) + delegateServiceAccountEmailOne := acctest.BootstrapServiceAccount(t, "delegate1", initialServiceAccount) // SA_2 + delegateServiceAccountEmailTwo := acctest.BootstrapServiceAccount(t, "delegate2", delegateServiceAccountEmailOne) // SA_3 + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "target", delegateServiceAccountEmailTwo) // SA_4 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountToken_withDelegates(initialServiceAccount, delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail, project), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountToken_withCustomLifetime(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "lifetime", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountToken_withCustomLifetime(targetServiceAccountEmail), + }, + }, + }) +} + +func testAccEphemeralServiceAccountToken_basic(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_access_token" "token" { + target_service_account = "%s" + scopes = ["https://www.googleapis.com/auth/cloud-platform"] +} +`, serviceAccountEmail) +} + +func testAccEphemeralServiceAccountToken_withDelegates(initialServiceAccountEmail, delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail, project string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_access_token" "test" { + target_service_account = "%s" + delegates = [ + "%s", + "%s", + ] + scopes = ["https://www.googleapis.com/auth/cloud-platform"] + lifetime = "3600s" +} + +# The delegation chain is: +# SA_1 (initialServiceAccountEmail) -> SA_2 (delegateServiceAccountEmailOne) -> SA_3 (delegateServiceAccountEmailTwo) -> SA_4 (targetServiceAccountEmail) +`, targetServiceAccountEmail, delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo) +} + +func testAccEphemeralServiceAccountToken_withCustomLifetime(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_access_token" "token" { + target_service_account = "%s" + scopes = ["https://www.googleapis.com/auth/cloud-platform"] + lifetime = "3600s" +} +`, serviceAccountEmail) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token.go new file mode 100644 index 000000000000..8de66a44c310 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token.go @@ -0,0 +1,166 @@ +package resourcemanager + +import ( + "context" + "fmt" + + "google.golang.org/api/idtoken" + "google.golang.org/api/option" + + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" + "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-google/google/fwutils" + "github.com/hashicorp/terraform-provider-google/google/fwvalidators" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "google.golang.org/api/iamcredentials/v1" +) + +var _ ephemeral.EphemeralResource = &googleEphemeralServiceAccountIdToken{} + +func GoogleEphemeralServiceAccountIdToken() ephemeral.EphemeralResource { + return &googleEphemeralServiceAccountIdToken{} +} + +type googleEphemeralServiceAccountIdToken struct { + providerConfig *transport_tpg.Config +} + +func (p *googleEphemeralServiceAccountIdToken) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_service_account_id_token" +} + +type ephemeralServiceAccountIdTokenModel struct { + TargetAudience types.String `tfsdk:"target_audience"` + TargetServiceAccount types.String `tfsdk:"target_service_account"` + Delegates types.Set `tfsdk:"delegates"` + IncludeEmail types.Bool `tfsdk:"include_email"` + IdToken types.String `tfsdk:"id_token"` +} + +func (p *googleEphemeralServiceAccountIdToken) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) { + resp.Schema.Description = "This ephemeral resource provides a Google OpenID Connect (oidc) id_token." + resp.Schema.MarkdownDescription = "This ephemeral resource provides a Google OpenID Connect (oidc) id_token." + + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "target_audience": schema.StringAttribute{ + Description: "The audience claim for the `id_token`.", + Required: true, + }, + "target_service_account": schema.StringAttribute{ + Description: "The email of the service account being impersonated. Used only when using impersonation mode.", + Optional: true, + Validators: []validator.String{ + fwvalidators.ServiceAccountEmailValidator{}, + }, + }, + "delegates": schema.SetAttribute{ + Description: "Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. Used only when using impersonation mode.", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.ValueStringsAre(fwvalidators.ServiceAccountEmailValidator{}), + }, + }, + "include_email": schema.BoolAttribute{ + Description: "Include the verified email in the claim. Used only when using impersonation mode.", + Optional: true, // Defaults to false when not set (Null / Unknown) + }, + "id_token": schema.StringAttribute{ + Description: "The `id_token` representing the new generated identity.", + Computed: true, + Sensitive: true, + }, + }, + } +} + +func (p *googleEphemeralServiceAccountIdToken) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + pd, ok := req.ProviderData.(*transport_tpg.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + p.providerConfig = pd +} + +func (p *googleEphemeralServiceAccountIdToken) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) { + var data ephemeralServiceAccountIdTokenModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + targetAudience := data.TargetAudience.ValueString() + + creds, err := p.providerConfig.GetCredentials([]string{userInfoScope}, false) + if err != nil { + resp.Diagnostics.AddError( + "error calling GetCredentials()", + err.Error(), + ) + return + } + + targetServiceAccount := data.TargetServiceAccount + // If a target service account is provided, use the API to generate the idToken + if !targetServiceAccount.IsNull() && !targetServiceAccount.IsUnknown() { + service := p.providerConfig.NewIamCredentialsClient(p.providerConfig.UserAgent) + name := fmt.Sprintf("projects/-/serviceAccounts/%s", targetServiceAccount.ValueString()) + + tokenRequest := &iamcredentials.GenerateIdTokenRequest{ + Audience: targetAudience, + IncludeEmail: data.IncludeEmail.ValueBool(), + Delegates: fwutils.StringSet(data.Delegates), + } + at, err := service.Projects.ServiceAccounts.GenerateIdToken(name, tokenRequest).Do() + if err != nil { + resp.Diagnostics.AddError( + "Error calling iamcredentials.GenerateIdToken", + err.Error(), + ) + return + } + + data.IdToken = types.StringValue(at.Token) + resp.Diagnostics.Append(resp.Result.Set(ctx, data)...) + return + } + + // If no target service account, use the default credentials + ctx = context.Background() + co := []option.ClientOption{} + if creds.JSON != nil { + co = append(co, idtoken.WithCredentialsJSON(creds.JSON)) + } + + idTokenSource, err := idtoken.NewTokenSource(ctx, targetAudience, co...) + if err != nil { + resp.Diagnostics.AddError( + "Unable to retrieve TokenSource", + err.Error(), + ) + return + } + idToken, err := idTokenSource.Token() + if err != nil { + resp.Diagnostics.AddError( + "Unable to retrieve Token", + err.Error(), + ) + return + } + + data.IdToken = types.StringValue(idToken.AccessToken) + resp.Diagnostics.Append(resp.Result.Set(ctx, data)...) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token_test.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token_test.go new file mode 100644 index 000000000000..8f66723bdd37 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_id_token_test.go @@ -0,0 +1,137 @@ +package resourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccEphemeralServiceAccountIdToken_basic(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "idtoken", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountIdToken_basic(targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountIdToken_withDelegates(t *testing.T) { + t.Parallel() + + initialServiceAccount := envvar.GetTestServiceAccountFromEnv(t) + delegateServiceAccountEmailOne := acctest.BootstrapServiceAccount(t, "id-delegate1", initialServiceAccount) // SA_2 + delegateServiceAccountEmailTwo := acctest.BootstrapServiceAccount(t, "id-delegate2", delegateServiceAccountEmailOne) // SA_3 + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "id-target", delegateServiceAccountEmailTwo) // SA_4 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountIdToken_withDelegates(delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountIdToken_withEmptyDelegates(t *testing.T) { + t.Parallel() + + initialServiceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "no-del", initialServiceAccount) // SA_4 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountIdToken_withEmptyDelegates(targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountIdToken_withIncludeEmail(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "idtoken-email", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountIdToken_withIncludeEmail(targetServiceAccountEmail), + }, + }, + }) +} + +func testAccEphemeralServiceAccountIdToken_basic(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_id_token" "token" { + target_service_account = "%s" + target_audience = "https://example.com" +} +`, serviceAccountEmail) +} + +func testAccEphemeralServiceAccountIdToken_withDelegates(delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_id_token" "token" { + target_service_account = "%s" + delegates = [ + "%s", + "%s", + ] + target_audience = "https://example.com" +} + +# The delegation chain is: +# SA_1 (initialServiceAccountEmail) -> SA_2 (delegateServiceAccountEmailOne) -> SA_3 (delegateServiceAccountEmailTwo) -> SA_4 (targetServiceAccountEmail) +`, targetServiceAccountEmail, delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo) +} + +func testAccEphemeralServiceAccountIdToken_withEmptyDelegates(targetServiceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_id_token" "token" { + target_service_account = "%s" + delegates = [] + target_audience = "https://example.com" +} +`, targetServiceAccountEmail) +} + +func testAccEphemeralServiceAccountIdToken_withIncludeEmail(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_id_token" "token" { + target_service_account = "%s" + target_audience = "https://example.com" + include_email = true +} +`, serviceAccountEmail) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt.go new file mode 100644 index 000000000000..bebc770558ca --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt.go @@ -0,0 +1,143 @@ +package resourcemanager + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" + "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-google/google/fwutils" + "github.com/hashicorp/terraform-provider-google/google/fwvalidators" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "google.golang.org/api/iamcredentials/v1" +) + +var _ ephemeral.EphemeralResource = &googleEphemeralServiceAccountJwt{} + +func GoogleEphemeralServiceAccountJwt() ephemeral.EphemeralResource { + return &googleEphemeralServiceAccountJwt{} +} + +type googleEphemeralServiceAccountJwt struct { + providerConfig *transport_tpg.Config +} + +func (p *googleEphemeralServiceAccountJwt) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_service_account_jwt" +} + +type ephemeralServiceAccountJwtModel struct { + Payload types.String `tfsdk:"payload"` + ExpiresIn types.Int64 `tfsdk:"expires_in"` + TargetServiceAccount types.String `tfsdk:"target_service_account"` + Delegates types.Set `tfsdk:"delegates"` + Jwt types.String `tfsdk:"jwt"` +} + +func (p *googleEphemeralServiceAccountJwt) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Produces an arbitrary self-signed JWT for service accounts.", + Attributes: map[string]schema.Attribute{ + "payload": schema.StringAttribute{ + Required: true, + Description: `A JSON-encoded JWT claims set that will be included in the signed JWT.`, + }, + "expires_in": schema.Int64Attribute{ + Optional: true, + Description: "Number of seconds until the JWT expires. If set and non-zero an `exp` claim will be added to the payload derived from the current timestamp plus expires_in seconds.", + Validators: []validator.Int64{ + int64validator.AtLeast(1), // Must be greater than 0 + }, + }, + "target_service_account": schema.StringAttribute{ + Description: "The email of the service account that will sign the JWT.", + Required: true, + Validators: []validator.String{ + fwvalidators.ServiceAccountEmailValidator{}, + }, + }, + "delegates": schema.SetAttribute{ + Description: "Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name.", + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.ValueStringsAre(fwvalidators.ServiceAccountEmailValidator{}), + }, + }, + "jwt": schema.StringAttribute{ + Description: "The signed JWT containing the JWT Claims Set from the `payload`.", + Computed: true, + Sensitive: true, + }, + }, + } +} + +func (p *googleEphemeralServiceAccountJwt) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + pd, ok := req.ProviderData.(*transport_tpg.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + p.providerConfig = pd +} + +func (p *googleEphemeralServiceAccountJwt) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) { + var data ephemeralServiceAccountJwtModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + payload := data.Payload.ValueString() + + if !data.ExpiresIn.IsNull() { + expiresIn := data.ExpiresIn.ValueInt64() + var decoded map[string]interface{} + if err := json.Unmarshal([]byte(payload), &decoded); err != nil { + resp.Diagnostics.AddError("Error decoding payload", err.Error()) + return + } + + decoded["exp"] = time.Now().Add(time.Duration(expiresIn) * time.Second).Unix() + + payloadBytesWithExp, err := json.Marshal(decoded) + if err != nil { + resp.Diagnostics.AddError("Error re-encoding payload", err.Error()) + return + } + + payload = string(payloadBytesWithExp) + + } + + name := fmt.Sprintf("projects/-/serviceAccounts/%s", data.TargetServiceAccount.ValueString()) + + service := p.providerConfig.NewIamCredentialsClient(p.providerConfig.UserAgent) + jwtRequest := &iamcredentials.SignJwtRequest{ + Payload: payload, + Delegates: fwutils.StringSet(data.Delegates), + } + + jwtResponse, err := service.Projects.ServiceAccounts.SignJwt(name, jwtRequest).Do() + if err != nil { + resp.Diagnostics.AddError("Error calling iamcredentials.SignJwt", err.Error()) + return + } + + data.Jwt = types.StringValue(jwtResponse.SignedJwt) + + resp.Diagnostics.Append(resp.Result.Set(ctx, data)...) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt_test.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt_test.go new file mode 100644 index 000000000000..89091c887bfd --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_jwt_test.go @@ -0,0 +1,106 @@ +package resourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccEphemeralServiceAccountJwt_basic(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "jwt-basic", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountJwt_basic(targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountJwt_withDelegates(t *testing.T) { + t.Parallel() + + initialServiceAccount := envvar.GetTestServiceAccountFromEnv(t) + delegateServiceAccountEmailOne := acctest.BootstrapServiceAccount(t, "jwt-delegate1", initialServiceAccount) // SA_2 + delegateServiceAccountEmailTwo := acctest.BootstrapServiceAccount(t, "jwt-delegate2", delegateServiceAccountEmailOne) // SA_3 + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "jwt-target", delegateServiceAccountEmailTwo) // SA_4 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountJwt_withDelegates(delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail), + }, + }, + }) +} + +func TestAccEphemeralServiceAccountJwt_withExpiresIn(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "expiry", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountJwt_withExpiresIn(targetServiceAccountEmail), + }, + }, + }) +} + +func testAccEphemeralServiceAccountJwt_basic(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_jwt" "jwt" { + target_service_account = "%s" + payload = jsonencode({ + "sub": "%[1]s", + "aud": "https://example.com" + }) +} +`, serviceAccountEmail) +} + +func testAccEphemeralServiceAccountJwt_withDelegates(delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo, targetServiceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_jwt" "jwt" { + target_service_account = "%s" + delegates = [ + "%s", + "%s", + ] + payload = jsonencode({ + "sub": "%[1]s", + "aud": "https://example.com" + }) +} +# The delegation chain is: +# SA_1 (initialServiceAccountEmail) -> SA_2 (delegateServiceAccountEmailOne) -> SA_3 (delegateServiceAccountEmailTwo) -> SA_4 (targetServiceAccountEmail) +`, targetServiceAccountEmail, delegateServiceAccountEmailOne, delegateServiceAccountEmailTwo) +} + +func testAccEphemeralServiceAccountJwt_withExpiresIn(serviceAccountEmail string) string { + return fmt.Sprintf(` +ephemeral "google_service_account_jwt" "jwt" { + target_service_account = "%s" + expires_in = 3600 + payload = jsonencode({ + "sub": "%[1]s", + "aud": "https://example.com" + }) +} +`, serviceAccountEmail) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key.go new file mode 100644 index 000000000000..327ee0f9be42 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key.go @@ -0,0 +1,126 @@ +package resourcemanager + +import ( + "context" + "fmt" + "regexp" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" + "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "github.com/hashicorp/terraform-provider-google/google/verify" +) + +var _ ephemeral.EphemeralResource = &googleEphemeralServiceAccountKey{} + +func GoogleEphemeralServiceAccountKey() ephemeral.EphemeralResource { + return &googleEphemeralServiceAccountKey{} +} + +type googleEphemeralServiceAccountKey struct { + providerConfig *transport_tpg.Config +} + +func (p *googleEphemeralServiceAccountKey) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_service_account_key" +} + +type ephemeralServiceAccountKeyModel struct { + Name types.String `tfsdk:"name"` + PublicKeyType types.String `tfsdk:"public_key_type"` + KeyAlgorithm types.String `tfsdk:"key_algorithm"` + PublicKey types.String `tfsdk:"public_key"` +} + +func (p *googleEphemeralServiceAccountKey) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Get an ephemeral service account public key.", + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Description: "The name of the service account key. This must have format `projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}/keys/{KEYID}`, where `{ACCOUNT}` is the email address or unique id of the service account.", + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexp.MustCompile(verify.ServiceAccountKeyNameRegex), + "must match regex: "+verify.ServiceAccountKeyNameRegex, + ), + }}, + "public_key_type": schema.StringAttribute{ + Description: "The output format of the public key requested. TYPE_X509_PEM_FILE is the default output format.", + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf( + "TYPE_X509_PEM_FILE", + "TYPE_RAW_PUBLIC_KEY", + ), + }, + }, + "key_algorithm": schema.StringAttribute{ + Description: "The algorithm used to generate the key.", + Computed: true, + }, + "public_key": schema.StringAttribute{ + Description: "The public key, base64 encoded.", + Computed: true, + }, + }, + } +} + +func (p *googleEphemeralServiceAccountKey) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + pd, ok := req.ProviderData.(*transport_tpg.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + p.providerConfig = pd +} + +func (p *googleEphemeralServiceAccountKey) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) { + var data ephemeralServiceAccountKeyModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + keyName := data.Name.ValueString() + + // Validate name + r := regexp.MustCompile(verify.ServiceAccountKeyNameRegex) + if !r.MatchString(keyName) { + resp.Diagnostics.AddError( + "Invalid key name", + fmt.Sprintf("Invalid key name %q does not match regexp %q", keyName, verify.ServiceAccountKeyNameRegex), + ) + return + } + + publicKeyType := data.PublicKeyType.ValueString() + if publicKeyType == "" { + publicKeyType = "TYPE_X509_PEM_FILE" + } + + sak, err := p.providerConfig.NewIamClient(p.providerConfig.UserAgent).Projects.ServiceAccounts.Keys.Get(keyName).PublicKeyType(publicKeyType).Do() + if err != nil { + resp.Diagnostics.AddError( + "Error retrieving Service Account Key", + fmt.Sprintf("Error retrieving Service Account Key %q: %s", keyName, err), + ) + return + } + + data.Name = types.StringValue(sak.Name) + data.KeyAlgorithm = types.StringValue(sak.KeyAlgorithm) + data.PublicKey = types.StringValue(sak.PublicKeyData) + + resp.Diagnostics.Append(resp.Result.Set(ctx, &data)...) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key_test.go b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key_test.go new file mode 100644 index 000000000000..e94bb5a46335 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/ephemeral_google_service_account_key_test.go @@ -0,0 +1,53 @@ +package resourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccEphemeralServiceAccountKey_basic(t *testing.T) { + t.Parallel() + + serviceAccount := envvar.GetTestServiceAccountFromEnv(t) + targetServiceAccountEmail := acctest.BootstrapServiceAccount(t, "key-basic", serviceAccount) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccEphemeralServiceAccountKey_setup(targetServiceAccountEmail), + }, + { + Config: testAccEphemeralServiceAccountKey_basic(targetServiceAccountEmail), + }, + }, + }) +} + +func testAccEphemeralServiceAccountKey_setup(serviceAccount string) string { + return fmt.Sprintf(` +resource "google_service_account_key" "key" { + service_account_id = "%s" + public_key_type = "TYPE_X509_PEM_FILE" +} +`, serviceAccount) +} + +func testAccEphemeralServiceAccountKey_basic(serviceAccount string) string { + return fmt.Sprintf(` +resource "google_service_account_key" "key" { + service_account_id = "%s" + public_key_type = "TYPE_X509_PEM_FILE" +} + +ephemeral "google_service_account_key" "key" { + name = google_service_account_key.key.name + public_key_type = "TYPE_X509_PEM_FILE" +} +`, serviceAccount) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_billing_subaccount_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_billing_subaccount_meta.yaml new file mode 100644 index 000000000000..896f474b1bac --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_billing_subaccount_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_billing_subaccount' +generation_type: 'handwritten' +api_service_name: 'cloudbilling.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'BillingAccount' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_meta.yaml new file mode 100644 index 000000000000..b88b40ee25a1 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_folder' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Folder' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_organization_policy_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_organization_policy_meta.yaml new file mode 100644 index 000000000000..9c7a0c24ccdf --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_folder_organization_policy_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_folder_organization_policy' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Folder' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_iam_custom_role_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_iam_custom_role_meta.yaml new file mode 100644 index 000000000000..711257ae01b4 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_iam_custom_role_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_organization_iam_custom_role' +generation_type: 'handwritten' +api_service_name: 'iam.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Role' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_policy_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_policy_meta.yaml new file mode 100644 index 000000000000..ad67418123b0 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_organization_policy_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_organization_policy' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Organization' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_default_service_accounts_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_default_service_accounts_meta.yaml new file mode 100644 index 000000000000..d606fe7c4e13 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_default_service_accounts_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project_default_service_accounts' +generation_type: 'handwritten' +api_service_name: 'iam.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ServiceAccount' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_custom_role_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_custom_role_meta.yaml new file mode 100644 index 000000000000..9617e5cd42bb --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_custom_role_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project_iam_custom_role' +generation_type: 'handwritten' +api_service_name: 'iam.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Role' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_member_remove_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_member_remove_meta.yaml new file mode 100644 index 000000000000..cac8201a0334 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_iam_member_remove_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project_iam_member_remove' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_meta.yaml new file mode 100644 index 000000000000..f27a48de4e8a --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_organization_policy_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_organization_policy_meta.yaml new file mode 100644 index 000000000000..8ffc2a275619 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_organization_policy_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project_organization_policy' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Project' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_service_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_service_meta.yaml new file mode 100644 index 000000000000..b408fdc49c94 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project_service_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_project_service' +generation_type: 'handwritten' +api_service_name: 'serviceusage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Service' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account.go b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account.go index 072619aab6d4..901b1d0ca975 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account.go +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account.go @@ -1,7 +1,9 @@ package resourcemanager import ( + "context" "fmt" + "log" "strings" "time" @@ -30,6 +32,7 @@ func ResourceGoogleServiceAccount() *schema.Resource { }, CustomizeDiff: customdiff.All( tpgresource.DefaultProviderProject, + resourceServiceAccountCustomDiff, ), Schema: map[string]*schema.Schema{ "email": { @@ -322,3 +325,34 @@ func resourceGoogleServiceAccountImport(d *schema.ResourceData, meta interface{} return []*schema.ResourceData{d}, nil } + +func ResourceServiceAccountCustomDiffFunc(diff tpgresource.TerraformResourceDiff) error { + if !tpgresource.IsNewResource(diff) && !diff.HasChange("account_id") { + return nil + } + + aid := diff.Get("account_id").(string) + proj := diff.Get("project").(string) + if aid == "" || proj == "" { + return nil + } + + email := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", aid, proj) + if err := diff.SetNew("email", email); err != nil { + return fmt.Errorf("error setting email: %s", err) + } + if err := diff.SetNew("member", "serviceAccount:"+email); err != nil { + return fmt.Errorf("error setting member: %s", err) + } + + return nil +} +func resourceServiceAccountCustomDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { + if ud := transport_tpg.GetUniverseDomainFromMeta(meta); ud != "googleapis.com" { + log.Printf("[WARN] The UniverseDomain is set to %q. Skipping resourceServiceAccountCustomDiff", ud) + return nil + } + + // separate func to allow unit testing + return ResourceServiceAccountCustomDiffFunc(diff) +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_key_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_key_meta.yaml new file mode 100644 index 000000000000..9abaeee5f9ca --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_key_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_service_account_key' +generation_type: 'handwritten' +api_service_name: 'iam.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Key' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_meta.yaml b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_meta.yaml new file mode 100644 index 000000000000..25273cda66be --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_service_account' +generation_type: 'handwritten' +api_service_name: 'iam.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ServiceAccount' diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_test.go b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_test.go index 2cb2c7a0d5c3..ca3708c9b127 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_test.go +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_service_account_test.go @@ -2,12 +2,16 @@ package resourcemanager_test import ( "fmt" + "maps" "testing" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-google/google/acctest" "github.com/hashicorp/terraform-provider-google/google/envvar" + tpgresourcemanager "github.com/hashicorp/terraform-provider-google/google/services/resourcemanager" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" ) // Test that a service account resource can be created, updated, and destroyed @@ -299,3 +303,107 @@ resource "google_service_account" "acceptance" { } `, account, name, desc, disabled) } + +func TestResourceServiceAccountCustomDiff(t *testing.T) { + t.Parallel() + + accountId := "a" + acctest.RandString(t, 10) + project := envvar.GetTestProjectFromEnv() + if project == "" { + project = "test-project" + } + expectedEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", accountId, project) + expectedMember := "serviceAccount:" + expectedEmail + + cases := []struct { + name string + before map[string]interface{} + after map[string]interface{} + wantEmail string + wantMember string + }{ + { + name: "normal (new)", + before: map[string]interface{}{}, + after: map[string]interface{}{ + "account_id": accountId, + "name": "", // Empty name indicates a new resource + "project": project, + }, + wantEmail: expectedEmail, + wantMember: expectedMember, + }, + { + name: "no change", + before: map[string]interface{}{ + "account_id": accountId, + "email": "dontchange", + "member": "dontchange", + "project": project, + }, + after: map[string]interface{}{ + "account_id": accountId, + "name": "unimportant", + "project": project, + }, + wantEmail: "", + wantMember: "", + }, + { + name: "recreate (new)", + before: map[string]interface{}{ + "account_id": "recreate-account", + "email": "recreate-email", + "member": "recreate-member", + "project": project, + }, + after: map[string]interface{}{ + "account_id": accountId, + "name": "", + "project": project, + }, + wantEmail: expectedEmail, + wantMember: expectedMember, + }, + { + name: "missing account_id (new)", + before: map[string]interface{}{}, + after: map[string]interface{}{ + "account_id": "", + "name": "", + "project": project, + }, + wantEmail: "", + wantMember: "", + }, + { + name: "missing project (new)", + before: map[string]interface{}{}, + after: map[string]interface{}{ + "account_id": accountId, + "name": "", + "project": "", + }, + wantEmail: "", + wantMember: "", + }, + } + for _, tc := range cases { + result := maps.Clone(tc.after) + if tc.wantEmail != "" || tc.wantMember != "" { + result["email"] = tc.wantEmail + result["member"] = tc.wantMember + } + t.Run(tc.name, func(t *testing.T) { + diff := &tpgresource.ResourceDiffMock{ + Before: tc.before, + After: tc.after, + Schema: tpgresourcemanager.ResourceGoogleServiceAccount().Schema, + } + tpgresourcemanager.ResourceServiceAccountCustomDiffFunc(diff) + if d := cmp.Diff(result, diff.After); d != "" { + t.Fatalf("got unexpected change: %v expected: %v", diff.After, result) + } + }) + } +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_project_service_identity_meta.yaml.tmpl b/mmv1/third_party/terraform/services/resourcemanager/resource_project_service_identity_meta.yaml.tmpl new file mode 100644 index 000000000000..60c35ff72cfb --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_project_service_identity_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_project_service_identity' +generation_type: 'handwritten' +api_service_name: 'serviceusage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Service' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_config_meta.yaml.tmpl b/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_config_meta.yaml.tmpl new file mode 100644 index 000000000000..996c58c77d70 --- /dev/null +++ b/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_config_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_runtimeconfig_config' +generation_type: 'handwritten' +api_service_name: 'runtimeconfig.googleapis.com' +api_version: 'v1beta1' +api_resource_type_kind: 'RuntimeConfig' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_variable_meta.yaml.tmpl b/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_variable_meta.yaml.tmpl new file mode 100644 index 000000000000..0cf5e15e6696 --- /dev/null +++ b/mmv1/third_party/terraform/services/runtimeconfig/resource_runtimeconfig_variable_meta.yaml.tmpl @@ -0,0 +1,7 @@ +{{ if ne $.TargetVersionName "ga" -}} +resource: 'google_runtimeconfig_variable' +generation_type: 'handwritten' +api_service_name: 'runtimeconfig.googleapis.com' +api_version: 'v1beta1' +api_resource_type_kind: 'Variable' +{{ end }} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/secretmanager/data_source_secret_manager_secrets_test.go b/mmv1/third_party/terraform/services/secretmanager/data_source_secret_manager_secrets_test.go index d457afe6a505..a58b2cfd1bba 100644 --- a/mmv1/third_party/terraform/services/secretmanager/data_source_secret_manager_secrets_test.go +++ b/mmv1/third_party/terraform/services/secretmanager/data_source_secret_manager_secrets_test.go @@ -231,7 +231,7 @@ func checkFieldsMatchForDataSourceStateAndResourceState(dsAttr, rsAttr map[strin return nil } -// This function checks state match for resourceName and asserts the absense of resourceName2 in data source +// This function checks state match for resourceName and asserts the absence of resourceName2 in data source func checkListDataSourceStateMatchesResourceStateWithIgnoresForAppliedFilter(dataSourceName, resourceName, resourceName2 string, ignoreFields map[string]struct{}) func(*terraform.State) error { return func(s *terraform.State) error { ds, ok := s.RootModule().Resources[dataSourceName] diff --git a/mmv1/third_party/terraform/services/securitycentermanagement/resource_scc_management_folder_security_health_analytics_custom_module_test.go.tmpl b/mmv1/third_party/terraform/services/securitycentermanagement/resource_scc_management_folder_security_health_analytics_custom_module_test.go.tmpl index d8b6433da018..053b6cc00b2c 100644 --- a/mmv1/third_party/terraform/services/securitycentermanagement/resource_scc_management_folder_security_health_analytics_custom_module_test.go.tmpl +++ b/mmv1/third_party/terraform/services/securitycentermanagement/resource_scc_management_folder_security_health_analytics_custom_module_test.go.tmpl @@ -15,7 +15,7 @@ import ( transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) -// Custom Module tests cannot be run in parallel without running into 409 Conflict reponses. +// Custom Module tests cannot be run in parallel without running into 409 Conflict responses. // Run them as individual steps of an update test instead. func testAccSecurityCenterManagementFolderSecurityHealthAnalyticsCustomModule(t *testing.T) { @@ -26,6 +26,9 @@ func testAccSecurityCenterManagementFolderSecurityHealthAnalyticsCustomModule(t "random_suffix": acctest.RandString(t, 10), } + // Log the organization ID for debugging purposes + t.Logf("Using Organization ID: %s", context["org_id"]) + acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), @@ -75,10 +78,9 @@ resource "google_folder" "folder" { deletion_protection = false } -resource "time_sleep" "wait_1_minute" { +resource "time_sleep" "wait_5_minute" { depends_on = [google_folder.folder] - - create_duration = "2m" + create_duration = "5m" } resource "google_scc_management_folder_security_health_analytics_custom_module" "example" { @@ -101,8 +103,7 @@ resource "google_scc_management_folder_security_health_analytics_custom_module" severity = "MEDIUM" } - - depends_on = [time_sleep.wait_1_minute] + depends_on = [time_sleep.wait_5_minute] } `, context) } @@ -116,6 +117,11 @@ resource "google_folder" "folder" { deletion_protection = false } +resource "time_sleep" "wait_5_minute" { + depends_on = [google_folder.folder] + create_duration = "5m" +} + resource "google_scc_management_folder_security_health_analytics_custom_module" "example" { provider = google-beta folder = google_folder.folder.folder_id @@ -149,6 +155,8 @@ resource "google_scc_management_folder_security_health_analytics_custom_module" description = "Description of the custom module" recommendation = "Steps to resolve violation" } + + depends_on = [time_sleep.wait_5_minute] } `, context) } @@ -162,6 +170,11 @@ resource "google_folder" "folder" { deletion_protection = false } +resource "time_sleep" "wait_5_minute" { + depends_on = [google_folder.folder] + create_duration = "5m" +} + resource "google_scc_management_folder_security_health_analytics_custom_module" "example" { provider = google-beta folder = google_folder.folder.folder_id @@ -195,6 +208,9 @@ resource "google_scc_management_folder_security_health_analytics_custom_module" description = "Updated description of the custom module" recommendation = "Updated steps to resolve violation" } + + depends_on = [time_sleep.wait_5_minute] + } `, context) } diff --git a/mmv1/third_party/terraform/services/servicemanagement/resource_endpoints_service_meta.yaml b/mmv1/third_party/terraform/services/servicemanagement/resource_endpoints_service_meta.yaml new file mode 100644 index 000000000000..92596bf91c15 --- /dev/null +++ b/mmv1/third_party/terraform/services/servicemanagement/resource_endpoints_service_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_endpoints_service' +generation_type: 'handwritten' +api_service_name: 'servicemanagement.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ManagedService' diff --git a/mmv1/third_party/terraform/services/servicenetworking/resource_google_service_networking_peered_dns_domain_meta.yaml b/mmv1/third_party/terraform/services/servicenetworking/resource_google_service_networking_peered_dns_domain_meta.yaml new file mode 100644 index 000000000000..07f91c6ec982 --- /dev/null +++ b/mmv1/third_party/terraform/services/servicenetworking/resource_google_service_networking_peered_dns_domain_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_service_networking_peered_dns_domain' +generation_type: 'handwritten' +api_service_name: 'servicenetworking.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'PeeredDnsDomain' diff --git a/mmv1/third_party/terraform/services/servicenetworking/resource_service_networking_connection_meta.yaml b/mmv1/third_party/terraform/services/servicenetworking/resource_service_networking_connection_meta.yaml new file mode 100644 index 000000000000..b39338c93c9c --- /dev/null +++ b/mmv1/third_party/terraform/services/servicenetworking/resource_service_networking_connection_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_service_networking_connection' +generation_type: 'handwritten' +api_service_name: 'servicenetworking.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Connection' diff --git a/mmv1/third_party/terraform/services/siteverification/resource_site_verification_owner_meta.yaml b/mmv1/third_party/terraform/services/siteverification/resource_site_verification_owner_meta.yaml new file mode 100644 index 000000000000..0f8a2b3448ce --- /dev/null +++ b/mmv1/third_party/terraform/services/siteverification/resource_site_verification_owner_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_site_verification_owner' +generation_type: 'handwritten' +api_service_name: 'siteverification.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'WebResource' diff --git a/mmv1/third_party/terraform/services/sql/data_source_sql_database_instances_test.go b/mmv1/third_party/terraform/services/sql/data_source_sql_database_instances_test.go index 4224dc317810..859204026991 100644 --- a/mmv1/third_party/terraform/services/sql/data_source_sql_database_instances_test.go +++ b/mmv1/third_party/terraform/services/sql/data_source_sql_database_instances_test.go @@ -327,7 +327,7 @@ func checkListDataSourceStateMatchesResourceStateWithIgnores(dataSourceName, res } } -// This function checks state match for resorceName2 and asserts the absense of resorceName in data source +// This function checks state match for resorceName2 and asserts the absence of resorceName in data source func checkListDataSourceStateMatchesResourceStateWithIgnoresForAppliedFilter(dataSourceName, resourceName, resourceName2 string, ignoreFields map[string]struct{}) func(*terraform.State) error { return func(s *terraform.State) error { ds, ok := s.RootModule().Resources[dataSourceName] @@ -373,7 +373,7 @@ func checkResourceAbsentInDataSourceAfterFilterApllied(dsAttr, rsAttr map[string return nil } -// This function checks whether all the attributes of the database instance resource and the attributes of the datbase instance inside the data source list are the same +// This function checks whether all the attributes of the database instance resource and the attributes of the database instance inside the data source list are the same func checkFieldsMatchForDataSourceStateAndResourceState(dsAttr, rsAttr map[string]string, ignoreFields map[string]struct{}) error { totalInstances, err := strconv.Atoi(dsAttr["instances.#"]) if err != nil { diff --git a/mmv1/third_party/terraform/services/sql/data_source_sql_databases_test.go b/mmv1/third_party/terraform/services/sql/data_source_sql_databases_test.go index c08450c43e64..1b476d03a5b8 100644 --- a/mmv1/third_party/terraform/services/sql/data_source_sql_databases_test.go +++ b/mmv1/third_party/terraform/services/sql/data_source_sql_databases_test.go @@ -107,7 +107,7 @@ func checkDatabasesListDataSourceStateMatchesResourceStateWithIgnores(dataSource } } -// This function checks whether all the attributes of the database instance resource and the attributes of the datbase instance inside the data source list are the same +// This function checks whether all the attributes of the database instance resource and the attributes of the database instance inside the data source list are the same func checkDatabaseFieldsMatchForDataSourceStateAndResourceState(dsAttr, rsAttr map[string]string, ignoreFields map[string]struct{}) error { totalInstances, err := strconv.Atoi(dsAttr["databases.#"]) if err != nil { diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl index fee345035643..3081fd57af5d 100644 --- a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance.go.tmpl @@ -727,7 +727,7 @@ is set to true. Defaults to ZONAL.`, "database_version": { Type: schema.TypeString, Required: true, - Description: `The MySQL, PostgreSQL or SQL Server (beta) version to use. Supported values include MYSQL_5_6, MYSQL_5_7, MYSQL_8_0, POSTGRES_9_6, POSTGRES_10, POSTGRES_11, POSTGRES_12, POSTGRES_13, POSTGRES_14, POSTGRES_15, SQLSERVER_2017_STANDARD, SQLSERVER_2017_ENTERPRISE, SQLSERVER_2017_EXPRESS, SQLSERVER_2017_WEB. Database Version Policies includes an up-to-date reference of supported versions.`, + Description: `The MySQL, PostgreSQL or SQL Server (beta) version to use. Supported values include MYSQL_5_6, MYSQL_5_7, MYSQL_8_0, POSTGRES_9_6, POSTGRES_10, POSTGRES_11, POSTGRES_12, POSTGRES_13, POSTGRES_14, POSTGRES_15, POSTGRES_16, POSTGRES_17, SQLSERVER_2017_STANDARD, SQLSERVER_2017_ENTERPRISE, SQLSERVER_2017_EXPRESS, SQLSERVER_2017_WEB. Database Version Policies includes an up-to-date reference of supported versions.`, }, "encryption_key_name": { @@ -831,7 +831,7 @@ is set to true. Defaults to ZONAL.`, "cascadable_replica": { Type: schema.TypeBool, Optional: true, - AtLeastOneOf: replicaConfigurationKeys, + AtLeastOneOf: replicaConfigurationKeys, Description: `Specifies if a SQL Server replica is a cascadable replica. A cascadable replica is a SQL Server cross region replica that supports replica(s) under it.`, }, "client_certificate": { @@ -1707,7 +1707,7 @@ func resourceSqlDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) e if err := d.Set("replica_configuration", flattenReplicaConfiguration(instance.ReplicaConfiguration, d)); err != nil { log.Printf("[WARN] Failed to set SQL Database Instance Replica Configuration") } - + if err := d.Set("replica_names", instance.ReplicaNames); err != nil { return fmt.Errorf("Error setting replica_names: %w", err) } @@ -2247,6 +2247,12 @@ func flattenSettings(settings *sqladmin.Settings, d *schema.ResourceData) []map[ if settings.DataCacheConfig != nil { data["data_cache_config"] = flattenDataCacheConfig(settings.DataCacheConfig) + } else { + data["data_cache_config"] = []map[string]interface{}{ + { + "data_cache_enabled": false, + }, + } } if settings.AdvancedMachineFeatures != nil { @@ -2258,7 +2264,11 @@ func flattenSettings(settings *sqladmin.Settings, d *schema.ResourceData) []map[ func flattenDataCacheConfig(d *sqladmin.DataCacheConfig) []map[string]interface{} { if d == nil { - return nil + return []map[string]interface{}{ + { + "data_cache_enabled": false, + }, + } } return []map[string]interface{}{ { @@ -2679,7 +2689,7 @@ func isSwitchoverFromOldPrimarySide(d *schema.ResourceDiff) bool { instanceTypeChangedFromPrimaryToReplica := oldInstanceType.(string) == "CLOUD_SQL_INSTANCE" && newInstanceType.(string) == "READ_REPLICA_INSTANCE" newMasterInOldReplicaNames := slices.Contains(oldReplicaNames.([]interface{}), newMasterInstanceName) newMasterNotInNewReplicaNames := !slices.Contains(newReplicaNames.([]interface{}), newMasterInstanceName) - isCascadableReplica := cascadableReplicaFieldExists && cascadableReplica.(bool) + isCascadableReplica := cascadableReplicaFieldExists && cascadableReplica.(bool) return newMasterInstanceName != nil && instanceTypeChangedFromPrimaryToReplica && @@ -2724,4 +2734,4 @@ func validatePromoteConfigurations(masterInstanceName cty.Value, replicaConfigur return fmt.Errorf("Replica promote configuration check failed. Please remove replica_configuration and try again.") } return nil -} \ No newline at end of file +} diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_meta.yaml b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_meta.yaml new file mode 100644 index 000000000000..1bb27fc50f14 --- /dev/null +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_sql_database_instance' +generation_type: 'handwritten' +api_service_name: 'sqladmin.googleapis.com' +api_version: 'v1beta4' +api_resource_type_kind: 'Instance' diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go index 98e1614f4929..fc5954744177 100644 --- a/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go +++ b/mmv1/third_party/terraform/services/sql/resource_sql_database_instance_test.go @@ -430,7 +430,7 @@ func TestAccSqlDatabaseInstance_replica(t *testing.T) { { Config: fmt.Sprintf( testGoogleSqlDatabaseInstance_replica, databaseID, databaseID, databaseID, "true"), - ExpectError: regexp.MustCompile("Error, failed to create instance tf-test-\\d+-2: googleapi: Error 400: Invalid request: Invalid flag for instance role: Backups cannot be enabled for read replica instance.., invalid"), + ExpectError: regexp.MustCompile("Error, failed to create instance tf-test-\\d+-2: googleapi: Error 400: Invalid request: Invalid flag for instance role: Backups cannot be enabled for read replica instance"), }, { Config: fmt.Sprintf( @@ -1058,7 +1058,7 @@ func TestAccSqlDatabaseInstance_withPSCEnabled_withIpV4Enabled(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccSqlDatabaseInstance_withPSCEnabled_withIpV4Enable(instanceName, projectId, orgId, billingAccount), - ExpectError: regexp.MustCompile("PSC connectivity cannot be enabled together with public IP"), + ExpectError: regexp.MustCompile("PSC connectivity cannot be enabled together with only public IP"), }, }, }) @@ -1755,9 +1755,9 @@ func TestAccSQLDatabaseInstance_sqlMysqlDataCacheConfig(t *testing.T) { CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(instanceName), + Config: testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(instanceName, false), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "true"), + resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "false"), ), }, { @@ -1766,6 +1766,12 @@ func TestAccSQLDatabaseInstance_sqlMysqlDataCacheConfig(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"deletion_protection"}, }, + { + Config: testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(instanceName, true), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "true"), + ), + }, }, }) } @@ -1782,7 +1788,7 @@ func TestAccSQLDatabaseInstance_sqlPostgresDataCacheConfig(t *testing.T) { CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(enterprisePlusInstanceName, enterprisePlusTier, "ENTERPRISE_PLUS"), + Config: testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(enterprisePlusInstanceName, enterprisePlusTier, "ENTERPRISE_PLUS", true), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "true"), ), @@ -1794,9 +1800,21 @@ func TestAccSQLDatabaseInstance_sqlPostgresDataCacheConfig(t *testing.T) { ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { - Config: testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(enterpriseInstanceName, enterpriseTier, "ENTERPRISE"), + Config: testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(enterprisePlusInstanceName, enterprisePlusTier, "ENTERPRISE_PLUS", false), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "false"), + ), + }, + { + ResourceName: "google_sql_database_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"deletion_protection"}, + }, + { + Config: testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(enterpriseInstanceName, enterpriseTier, "ENTERPRISE", true), ExpectError: regexp.MustCompile( - fmt.Sprintf("Error, failed to create instance %s: googleapi: Error 400: Invalid request: Only ENTERPRISE PLUS edition supports data cache.., invalid", enterpriseInstanceName)), + fmt.Sprintf("Error, failed to create instance %s: googleapi: Error 400: Invalid request: Only ENTERPRISE PLUS edition supports data cache", enterpriseInstanceName)), }, }, }) @@ -1824,7 +1842,7 @@ func TestAccSqlDatabaseInstance_Mysql_Edition_Upgrade(t *testing.T) { ImportStateVerifyIgnore: []string{"deletion_protection"}, }, { - Config: testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(editionUpgrade), + Config: testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(editionUpgrade, true), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.edition", "ENTERPRISE_PLUS"), resource.TestCheckResourceAttr("google_sql_database_instance.instance", "settings.0.data_cache_config.0.data_cache_enabled", "true"), @@ -2899,7 +2917,7 @@ resource "google_sql_database_instance" "instance" { }`, databaseName, tier) } -func testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(instanceName string) string { +func testGoogleSqlDatabaseInstance_sqlMysqlDataCacheConfig(instanceName string, datacache bool) string { return fmt.Sprintf(` resource "google_sql_database_instance" "instance" { @@ -2911,13 +2929,13 @@ resource "google_sql_database_instance" "instance" { tier = "db-perf-optimized-N-2" edition = "ENTERPRISE_PLUS" data_cache_config { - data_cache_enabled = true + data_cache_enabled = "%t" } } -}`, instanceName) +}`, instanceName, datacache) } -func testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(instanceName, tier, edition string) string { +func testGoogleSqlDatabaseInstance_sqlPostgresDataCacheConfig(instanceName, tier, edition string, datacache bool) string { return fmt.Sprintf(` resource "google_sql_database_instance" "instance" { @@ -2929,10 +2947,10 @@ resource "google_sql_database_instance" "instance" { tier = "%s" edition = "%s" data_cache_config { - data_cache_enabled = true + data_cache_enabled = "%t" } } -}`, instanceName, tier, edition) +}`, instanceName, tier, edition, datacache) } func testGoogleSqlDatabaseInstance_SqlServerTimezone(instance, rootPassword, timezone string) string { diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_ssl_cert_meta.yaml b/mmv1/third_party/terraform/services/sql/resource_sql_ssl_cert_meta.yaml new file mode 100644 index 000000000000..1723d2c37b62 --- /dev/null +++ b/mmv1/third_party/terraform/services/sql/resource_sql_ssl_cert_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_sql_ssl_cert' +generation_type: 'handwritten' +api_service_name: 'sqladmin.googleapis.com' +api_version: 'v1beta4' +api_resource_type_kind: 'SslCert' diff --git a/mmv1/third_party/terraform/services/sql/resource_sql_user_meta.yaml b/mmv1/third_party/terraform/services/sql/resource_sql_user_meta.yaml new file mode 100644 index 000000000000..e70e60cadfe8 --- /dev/null +++ b/mmv1/third_party/terraform/services/sql/resource_sql_user_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_sql_user' +generation_type: 'handwritten' +api_service_name: 'sqladmin.googleapis.com' +api_version: 'v1beta4' +api_resource_type_kind: 'User' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_acl_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_acl_meta.yaml new file mode 100644 index 000000000000..4a8a1aa4171a --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_acl_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_bucket_acl' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'BucketAccessControl' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_meta.yaml new file mode 100644 index 000000000000..f86d83bc8b1d --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_bucket' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Bucket' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object.go b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object.go index eb6ee62ca0b2..1023a9b3d067 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object.go +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object.go @@ -3,6 +3,7 @@ package storage import ( "bytes" + "context" "fmt" "io" "log" @@ -24,10 +25,11 @@ import ( func ResourceStorageBucketObject() *schema.Resource { return &schema.Resource{ - Create: resourceStorageBucketObjectCreate, - Read: resourceStorageBucketObjectRead, - Update: resourceStorageBucketObjectUpdate, - Delete: resourceStorageBucketObjectDelete, + Create: resourceStorageBucketObjectCreate, + Read: resourceStorageBucketObjectRead, + Update: resourceStorageBucketObjectUpdate, + Delete: resourceStorageBucketObjectDelete, + CustomizeDiff: resourceStorageBucketObjectCustomizeDiff, Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(4 * time.Minute), @@ -603,3 +605,35 @@ func flattenObjectRetention(objectRetention *storage.ObjectRetention) []map[stri retentions = append(retentions, retention) return retentions } + +func resourceStorageBucketObjectCustomizeDiff(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { + localMd5Hash := "" + if source, ok := d.GetOkExists("source"); ok { + localMd5Hash = tpgresource.GetFileMd5Hash(source.(string)) + } + if content, ok := d.GetOkExists("content"); ok { + localMd5Hash = tpgresource.GetContentMd5Hash([]byte(content.(string))) + } + if localMd5Hash == "" { + return nil + } + + oldMd5Hash, ok := d.GetOkExists("md5hash") + if ok && oldMd5Hash == localMd5Hash { + return nil + } + + err := d.SetNewComputed("md5hash") + if err != nil { + return fmt.Errorf("Error re-setting md5hash: %s", err) + } + err = d.SetNewComputed("crc32c") + if err != nil { + return fmt.Errorf("Error re-setting crc32c: %s", err) + } + err = d.SetNewComputed("generation") + if err != nil { + return fmt.Errorf("Error re-setting generation: %s", err) + } + return nil +} diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object_meta.yaml new file mode 100644 index 000000000000..2c69c0c14139 --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_object_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_bucket_object' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'Object' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.tmpl b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.tmpl index b5df505fc00c..e86f00d6f918 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go.tmpl @@ -109,7 +109,7 @@ func TestAccStorageBucket_basicWithAutoclass(t *testing.T) { }) } -func TestAccStorageBucket_AutoclassDiffSupress(t *testing.T) { +func TestAccStorageBucket_AutoclassDiffSuppress(t *testing.T) { t.Parallel() var bucket storage.Bucket diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_default_object_acl_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_default_object_acl_meta.yaml new file mode 100644 index 000000000000..6572312da7b2 --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_default_object_acl_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_default_object_acl' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ObjectAccessControl' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_notification_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_notification_meta.yaml new file mode 100644 index 000000000000..d06f98fcd331 --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_notification_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_notification' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'NotificationConfig' diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_object_acl_meta.yaml b/mmv1/third_party/terraform/services/storage/resource_storage_object_acl_meta.yaml new file mode 100644 index 000000000000..2dd0a823b055 --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_object_acl_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_object_acl' +generation_type: 'handwritten' +api_service_name: 'storage.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'ObjectAccessControl' diff --git a/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job.go.tmpl b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job.go.tmpl index a901c6885194..f5746498c47f 100644 --- a/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job.go.tmpl +++ b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job.go.tmpl @@ -41,6 +41,7 @@ var ( "transfer_spec.0.http_data_source", "transfer_spec.0.azure_blob_storage_data_source", "transfer_spec.0.posix_data_source", + "transfer_spec.0.hdfs_data_source", } transferSpecDataSinkKeys = []string{ "transfer_spec.0.gcs_data_sink", @@ -197,6 +198,14 @@ func ResourceStorageTransferJob() *schema.Resource { ExactlyOneOf: transferSpecDataSourceKeys, Description: `An Azure Blob Storage data source.`, }, + "hdfs_data_source": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: hdfsDataSchema(), + ExactlyOneOf: transferSpecDataSourceKeys, + Description: `An HDFS Storage data source.`, + }, }, }, Description: `Transfer specification.`, @@ -545,6 +554,18 @@ func posixDataSchema() *schema.Resource { } } +func hdfsDataSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "path": { + Type: schema.TypeString, + Required: true, + Description: `Directory path to the filesystem.`, + }, + }, + } +} + func azureBlobStorageDataSchema() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -1105,6 +1126,25 @@ func flattenPosixData(posixData *storagetransfer.PosixFilesystem) []map[string]i return []map[string]interface{}{data} } +func expandHdfsData(hdfsDatas []interface{}) *storagetransfer.HdfsData { + if len(hdfsDatas) == 0 || hdfsDatas[0] == nil { + return nil + } + + hdfsData := hdfsDatas[0].(map[string]interface{}) + return &storagetransfer.HdfsData{ + Path: hdfsData["path"].(string), + } +} + +func flattenHdfsData(hdfsData *storagetransfer.HdfsData) []map[string]interface{} { + data := map[string]interface{}{ + "path": hdfsData.Path, + } + + return []map[string]interface{}{data} +} + func expandAzureCredentials(azureCredentials []interface{}) *storagetransfer.AzureCredentials { if len(azureCredentials) == 0 || azureCredentials[0] == nil { return nil @@ -1232,6 +1272,7 @@ func expandTransferSpecs(transferSpecs []interface{}) *storagetransfer.TransferS HttpDataSource: expandHttpData(transferSpec["http_data_source"].([]interface{})), AzureBlobStorageDataSource: expandAzureBlobStorageData(transferSpec["azure_blob_storage_data_source"].([]interface{})), PosixDataSource: expandPosixData(transferSpec["posix_data_source"].([]interface{})), + HdfsDataSource: expandHdfsData(transferSpec["hdfs_data_source"].([]interface{})), } } @@ -1267,6 +1308,8 @@ func flattenTransferSpec(transferSpec *storagetransfer.TransferSpec, d *schema.R data["azure_blob_storage_data_source"] = flattenAzureBlobStorageData(transferSpec.AzureBlobStorageDataSource, d) } else if transferSpec.PosixDataSource != nil { data["posix_data_source"] = flattenPosixData(transferSpec.PosixDataSource) + } else if transferSpec.HdfsDataSource != nil { + data["hdfs_data_source"] = flattenHdfsData(transferSpec.HdfsDataSource) } return []map[string]interface{}{data} diff --git a/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_meta.yaml b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_meta.yaml new file mode 100644 index 000000000000..e7e13025224d --- /dev/null +++ b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_storage_transfer_job' +generation_type: 'handwritten' +api_service_name: 'storagetransfer.googleapis.com' +api_version: 'v1' +api_resource_type_kind: 'TransferJob' diff --git a/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_test.go b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_test.go index 39c9dba9257f..e356df62d195 100644 --- a/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_test.go +++ b/mmv1/third_party/terraform/services/storagetransfer/resource_storage_transfer_job_test.go @@ -369,6 +369,39 @@ func TestAccStorageTransferJob_notificationConfig(t *testing.T) { }) } +func TestAccStorageTransferJob_hdfsSource(t *testing.T) { + t.Parallel() + + testDataSinkName := acctest.RandString(t, 10) + otherDataSinkName := acctest.RandString(t, 10) + testTransferJobDescription := acctest.RandString(t, 10) + testSourceAgentPoolName := fmt.Sprintf("tf-test-source-agent-pool-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccStorageTransferJobDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccStorageTransferJob_hdfsSource(envvar.GetTestProjectFromEnv(), testDataSinkName, testTransferJobDescription, testSourceAgentPoolName, "/root/", ""), + }, + { + ResourceName: "google_storage_transfer_job.transfer_job", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccStorageTransferJob_hdfsSource(envvar.GetTestProjectFromEnv(), otherDataSinkName, testTransferJobDescription, testSourceAgentPoolName, "/root/dir/", "object/"), + }, + { + ResourceName: "google_storage_transfer_job.transfer_job", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccStorageTransferJobDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { config := acctest.GoogleProviderConfig(t) @@ -950,6 +983,83 @@ resource "google_storage_transfer_job" "transfer_job" { `, project, dataSinkBucketName, project, sourceAgentPoolName, transferJobDescription, project) } +func testAccStorageTransferJob_hdfsSource(project string, dataSinkBucketName string, transferJobDescription string, sourceAgentPoolName string, hdfsPath string, gcsPath string) string { + return fmt.Sprintf(` +data "google_storage_transfer_project_service_account" "default" { + project = "%s" +} + +resource "google_storage_bucket" "data_sink" { + name = "%s" + project = "%s" + location = "US" + force_destroy = true + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_iam_member" "data_sink" { + bucket = google_storage_bucket.data_sink.name + role = "roles/storage.admin" + member = "serviceAccount:${data.google_storage_transfer_project_service_account.default.email}" +} + +resource "google_project_iam_member" "pubsub" { + project = data.google_storage_transfer_project_service_account.default.project + role = "roles/pubsub.admin" + member = "serviceAccount:${data.google_storage_transfer_project_service_account.default.email}" +} + +resource "google_storage_transfer_agent_pool" "foo" { + name = "%s" + bandwidth_limit { + limit_mbps = "120" + } + + depends_on = [google_project_iam_member.pubsub] +} + +resource "google_storage_transfer_job" "transfer_job" { + description = "%s" + project = "%s" + + transfer_spec { + source_agent_pool_name = google_storage_transfer_agent_pool.foo.id + hdfs_data_source { + path = "%s" + } + gcs_data_sink { + bucket_name = google_storage_bucket.data_sink.name + path = "%s" + } + } + + schedule { + schedule_start_date { + year = 2018 + month = 10 + day = 1 + } + schedule_end_date { + year = 2019 + month = 10 + day = 1 + } + start_time_of_day { + hours = 0 + minutes = 30 + seconds = 0 + nanos = 0 + } + } + + depends_on = [ + google_storage_bucket_iam_member.data_sink, + google_project_iam_member.pubsub + ] +} +`, project, dataSinkBucketName, project, sourceAgentPoolName, transferJobDescription, project, hdfsPath, gcsPath) +} + func testAccStorageTransferJob_posixSink(project string, dataSourceBucketName string, transferJobDescription string, sinkAgentPoolName string) string { return fmt.Sprintf(` data "google_storage_transfer_project_service_account" "default" { diff --git a/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.tmpl b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding.go.tmpl similarity index 99% rename from mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.tmpl rename to mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding.go.tmpl index d05333b94808..c729994f45b5 100644 --- a/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_bindings.go.tmpl +++ b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding.go.tmpl @@ -352,7 +352,6 @@ func flattenNestedTagsLocationTagBinding(d *schema.ResourceData, meta interface{ switch v.(type) { case []interface{}: log.Printf("[DEBUG] Hey it's in break = %#v,)", v) - break case map[string]interface{}: // Construct list out of single nested resource v = []interface{}{v} diff --git a/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding_meta.yaml b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding_meta.yaml new file mode 100644 index 000000000000..b54d7fe1a0e2 --- /dev/null +++ b/mmv1/third_party/terraform/services/tags/resource_tags_location_tag_binding_meta.yaml @@ -0,0 +1,5 @@ +resource: 'google_tags_location_tag_binding' +generation_type: 'handwritten' +api_service_name: 'cloudresourcemanager.googleapis.com' +api_version: 'v3' +api_resource_type_kind: 'TagBinding' diff --git a/mmv1/third_party/terraform/sweeper/gcp_sweeper.go b/mmv1/third_party/terraform/sweeper/gcp_sweeper.go index 4cde53947aa8..6f19cd0499bb 100644 --- a/mmv1/third_party/terraform/sweeper/gcp_sweeper.go +++ b/mmv1/third_party/terraform/sweeper/gcp_sweeper.go @@ -21,6 +21,7 @@ var testResourcePrefixes = []string{ // include a "-" or "_" respectively, and they are the preferred prefix for our test resources to use "tf-test", "tf_test", + // Resource-specific prefixes that should be moved to the corresponding resource sweeper as part of https://github.com/hashicorp/terraform-provider-google/issues/20638 "tfgen", "gke-us-central1-tf", // composer-created disks which are abandoned by design (https://cloud.google.com/composer/pricing) "gcs-bucket-tf-test-", // https://github.com/hashicorp/terraform-provider-google/issues/8909 @@ -28,6 +29,7 @@ var testResourcePrefixes = []string{ "resourcegroup-", // https://github.com/hashicorp/terraform-provider-google/issues/8924 "cluster-", // https://github.com/hashicorp/terraform-provider-google/issues/8924 "k8s-fw-", // firewall rules are getting created and not cleaned up by k8 resources using this prefix + "ext-tf-test", // Cloud Tasks Queues created automatically by tests for `google_firebase_extensions_instance`. } // SharedConfigForRegion returns a common config setup needed for the sweeper diff --git a/mmv1/third_party/terraform/tpgresource/annotations.go b/mmv1/third_party/terraform/tpgresource/annotations.go index bfe0e14d287c..2c639aa596a9 100644 --- a/mmv1/third_party/terraform/tpgresource/annotations.go +++ b/mmv1/third_party/terraform/tpgresource/annotations.go @@ -97,7 +97,7 @@ func SetMetadataAnnotationsDiff(_ context.Context, d *schema.ResourceDiff, meta // Sets the "annotations" field with the value of the field "effective_annotations" for data sources. // When reading data source, as the annotations field is unavailable in the configuration of the data source, -// the "annotations" field will be empty. With this funciton, the labels "annotations" will have all of annotations in the resource. +// the "annotations" field will be empty. With this function, the labels "annotations" will have all of annotations in the resource. func SetDataSourceAnnotations(d *schema.ResourceData) error { effectiveAnnotations := d.Get("effective_annotations") if effectiveAnnotations == nil { diff --git a/mmv1/third_party/terraform/tpgresource/labels.go b/mmv1/third_party/terraform/tpgresource/labels.go index 7db1a6305e66..c5d5abfe3e54 100644 --- a/mmv1/third_party/terraform/tpgresource/labels.go +++ b/mmv1/third_party/terraform/tpgresource/labels.go @@ -31,7 +31,7 @@ func SetLabels(labels map[string]string, d *schema.ResourceData, lineage string) // Sets the "labels" field and "terraform_labels" with the value of the field "effective_labels" for data sources. // When reading data source, as the labels field is unavailable in the configuration of the data source, -// the "labels" field will be empty. With this funciton, the labels "field" will have all of labels in the resource. +// the "labels" field will be empty. With this function, the labels "field" will have all of labels in the resource. func SetDataSourceLabels(d *schema.ResourceData) error { effectiveLabels := d.Get("effective_labels") if effectiveLabels == nil { diff --git a/mmv1/third_party/terraform/tpgresource/resource_test_utils.go b/mmv1/third_party/terraform/tpgresource/resource_test_utils.go index a80090613f2d..20879192dc7c 100644 --- a/mmv1/third_party/terraform/tpgresource/resource_test_utils.go +++ b/mmv1/third_party/terraform/tpgresource/resource_test_utils.go @@ -79,6 +79,7 @@ type ResourceDiffMock struct { Before map[string]interface{} After map[string]interface{} Cleared map[string]interface{} + Schema map[string]*schema.Schema IsForceNew bool } @@ -113,6 +114,32 @@ func (d *ResourceDiffMock) ForceNew(key string) error { return nil } +func (d *ResourceDiffMock) SetNew(key string, value interface{}) error { + if len(d.Schema) > 0 { + if err := d.checkKey(key, "SetNew"); err != nil { + return err + } + } + + d.After[key] = value + return nil +} + +func (d *ResourceDiffMock) checkKey(key, caller string) error { + var schema *schema.Schema + s, ok := d.Schema[key] + if ok { + schema = s + } + if schema == nil { + return fmt.Errorf("%s: invalid key: %s", caller, key) + } + if !schema.Computed { + return fmt.Errorf("%s only operates on computed keys - %s is not one", caller, key) + } + return nil +} + // This function isn't a test of transport.go; instead, it is used as an alternative // to ReplaceVars inside tests. func ReplaceVarsForTest(config *transport_tpg.Config, rs *terraform.ResourceState, linkTmpl string) (string, error) { diff --git a/mmv1/third_party/terraform/tpgresource/utils.go b/mmv1/third_party/terraform/tpgresource/utils.go index 30be51214971..378d8ec19f23 100644 --- a/mmv1/third_party/terraform/tpgresource/utils.go +++ b/mmv1/third_party/terraform/tpgresource/utils.go @@ -54,6 +54,7 @@ type TerraformResourceDiff interface { GetOk(string) (interface{}, bool) Clear(string) error ForceNew(string) error + SetNew(string, interface{}) error } // Contains functions that don't really belong anywhere else. diff --git a/mmv1/third_party/terraform/transport/config.go.tmpl b/mmv1/third_party/terraform/transport/config.go.tmpl index 94506f6230c9..a3e7f323358a 100644 --- a/mmv1/third_party/terraform/transport/config.go.tmpl +++ b/mmv1/third_party/terraform/transport/config.go.tmpl @@ -64,6 +64,9 @@ import ( dataflow "google.golang.org/api/dataflow/v1b3" "google.golang.org/api/dataproc/v1" "google.golang.org/api/dns/v1" +{{- if ne $.TargetVersionName "ga" }} + firebase "google.golang.org/api/firebase/v1beta1" +{{- end }} healthcare "google.golang.org/api/healthcare/v1" "google.golang.org/api/iam/v1" iamcredentials "google.golang.org/api/iamcredentials/v1" @@ -203,7 +206,7 @@ type Config struct { UserAgent string gRPCLoggingOptions []option.ClientOption - tokenSource oauth2.TokenSource + TokenSource oauth2.TokenSource {{ range $product := $.Products }} {{ $product.Name }}BasePath string @@ -431,7 +434,7 @@ func (c *Config) LoadAndValidate(ctx context.Context) error { return err } - c.tokenSource = tokenSource + c.TokenSource = tokenSource cleanCtx := context.WithValue(ctx, oauth2.HTTPClient, cleanhttp.DefaultClient()) @@ -660,6 +663,23 @@ func (c *Config) NewDnsClient(userAgent string) *dns.Service { return clientDns } +{{- if ne $.TargetVersionName "ga" }} +func (c *Config) NewFirebaseClient(ctx context.Context, userAgent string) *firebase.Service { + firebaseClientBasePath := RemoveBasePathVersion(c.FirebaseBasePath) + firebaseClientBasePath = strings.ReplaceAll(firebaseClientBasePath, "/firebase/", "") + log.Printf("[INFO] Instantiating Google Cloud firebase client for path %s", firebaseClientBasePath) + clientFirebase, err := firebase.NewService(c.Context, option.WithHTTPClient(c.Client)) + if err != nil { + log.Printf("[WARN] Error creating client firebase: %s", err) + return nil + } + clientFirebase.UserAgent = userAgent + clientFirebase.BasePath = firebaseClientBasePath + + return clientFirebase +} +{{- end }} + func (c *Config) NewKmsClientWithCtx(ctx context.Context, userAgent string) *cloudkms.Service { kmsClientBasePath := RemoveBasePathVersion(c.KMSBasePath) log.Printf("[INFO] Instantiating Google Cloud KMS client for path %s", kmsClientBasePath) @@ -1073,7 +1093,7 @@ func (c *Config) NewCloudIdentityClient(userAgent string) *cloudidentity.Service func (c *Config) BigTableClientFactory(userAgent string) *BigtableClientFactory { bigtableClientFactory := &BigtableClientFactory{ UserAgent: userAgent, - TokenSource: c.tokenSource, + TokenSource: c.TokenSource, gRPCLoggingOptions: c.gRPCLoggingOptions, BillingProject: c.BillingProject, UserProjectOverride: c.UserProjectOverride, @@ -1352,3 +1372,11 @@ func GetRegionFromRegionSelfLink(selfLink string) string { } return selfLink } + +func GetUniverseDomainFromMeta(meta interface{}) string { + config := meta.(*Config) + if config.UniverseDomain == "" { + return "googleapis.com" + } + return config.UniverseDomain +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/transport/error_retry_predicates.go b/mmv1/third_party/terraform/transport/error_retry_predicates.go index ac239ee4c641..75922e1d9436 100644 --- a/mmv1/third_party/terraform/transport/error_retry_predicates.go +++ b/mmv1/third_party/terraform/transport/error_retry_predicates.go @@ -115,6 +115,21 @@ func is409OperationInProgressError(err error) (bool, string) { return false, "" } +// Code Repository Index is a long running operation +// The resource takes time to change it's state from "CREATING" to "ACTIVE" +func IsCodeRepositoryIndexUnreadyError(err error) (bool, string) { + gerr, ok := err.(*googleapi.Error) + if !ok { + return false, "" + } + + if gerr.Code == 409 && strings.Contains(gerr.Body, "parent resource not in ready state") { + log.Printf("[DEBUG] Dismissed an error as retryable based on error code 409 and error reason 'parent resource not in ready state': %s", err) + return true, "CodeRepositoryIndex not ready" + } + return false, "" +} + func isSubnetworkUnreadyError(err error) (bool, string) { gerr, ok := err.(*googleapi.Error) if !ok { @@ -259,6 +274,17 @@ func IsBigqueryIAMQuotaError(err error) (bool, string) { return false, "" } +// Retry if Repository Group operation returns a 409 with a specific message for +// enqueued operations. +func IsRepositoryGroupQueueError(err error) (bool, string) { + if gerr, ok := err.(*googleapi.Error); ok { + if gerr.Code == 409 && (strings.Contains(strings.ToLower(gerr.Body), "unable to queue the operation")) { + return true, "Waiting for other enqueued operations to finish" + } + } + return false, "" +} + // Retry if Monitoring operation returns a 409 with a specific message for // concurrent operations. func IsMonitoringConcurrentEditError(err error) (bool, string) { diff --git a/mmv1/third_party/terraform/website/docs/d/backup_dr_backup.html.markdown b/mmv1/third_party/terraform/website/docs/d/backup_dr_backup.html.markdown new file mode 100644 index 000000000000..ca31d46d9824 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/backup_dr_backup.html.markdown @@ -0,0 +1,29 @@ +--- +subcategory: "Backup and DR Backup" +description: |- + Get information about a Backupdr Backup. +--- + +# google_backup_dr_backup + +A Backup and DR Backup. + +## Example Usage + +```hcl +data "google_backup_dr_backup" "foo" { + location = "us-central1" + project = "project-test" + data_source_id = "ds-test" + backup_vault_id = "bv-test" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - (Required) The location in which the Backup belongs. +* `project` - (Required) The Google Cloud Project in which the Backup belongs. +* `data_source_id` - (Required) The ID of the Data Source in which the Backup belongs. +* `backup_vault_id` - (Required) The ID of the Backup Vault of the Data Source in which the Backup belongs. \ No newline at end of file diff --git a/mmv1/third_party/terraform/website/docs/d/backup_dr_backup_vault.html.markdown b/mmv1/third_party/terraform/website/docs/d/backup_dr_backup_vault.html.markdown new file mode 100644 index 000000000000..5e819723211b --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/backup_dr_backup_vault.html.markdown @@ -0,0 +1,34 @@ +--- +subcategory: "Backup and DR BackupVault" +description: |- + Get information about a Backupdr BackupVault. +--- + +# google_backup_dr_backup_vault + +A Backup and DRBackupVault. + +## Example Usage + +```hcl +data "google_backup_dr_backup_vault" "my-backup-vault" { + location = "us-central1" + backup_vault_id="bv-1" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - (Required) The location in which the Backup Vault resource belongs. +* `backup_vault_id` - (Required) The id of Backup Vault resource. + +- - - + +* `project` - (Optional) The project in which the resource belongs. If it + is not provided, the provider project is used. + +## Attributes Reference + +See [google_backup_dr_backup_vault](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/backup_dr_backup_vault) resource for details of the available attributes. \ No newline at end of file diff --git a/mmv1/third_party/terraform/website/docs/d/backup_dr_data_source.html.markdown b/mmv1/third_party/terraform/website/docs/d/backup_dr_data_source.html.markdown new file mode 100644 index 000000000000..13d794e27721 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/backup_dr_data_source.html.markdown @@ -0,0 +1,29 @@ +--- +subcategory: "Backup and DR Data Source" +description: |- + Get information about a Backupdr Data Source. +--- + +# google_backup_dr_data_source + +A Backup and DR Data Source. + +## Example Usage + +```hcl +data "google_backup_dr_data_source" "foo" { + location = "us-central1" + project = "project-test" + data_source_id = "ds-test" + backup_vault_id = "bv-test" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `location` - (Required) The location in which the Data Source belongs. +* `project` - (Required) The Google Cloud Project in which the Data Source belongs. +* `data_source_id` - (Required) The ID of the Data Source. +* `backup_vault_id` - (Required) The ID of the Backup Vault in which the Data Source belongs. \ No newline at end of file diff --git a/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_config_map.html.markdown b/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_config_map.html.markdown index f582d646df88..00e2a0d4a27f 100644 --- a/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_config_map.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_config_map.html.markdown @@ -8,9 +8,6 @@ description: |- Provides access to Kubernetes ConfigMap configuration for a given project, region and Composer Environment. -> **Warning:** This data source is in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. - ## Example Usage ```hcl diff --git a/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_secret.html.markdown b/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_secret.html.markdown index 93f5356a781f..3b7f61b87562 100644 --- a/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_secret.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/composer_user_workloads_secret.html.markdown @@ -8,9 +8,6 @@ description: |- Provides access to Kubernetes Secret configuration for a given project, region and Composer Environment. -~> **Warning:** This data source is in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. - ## Example Usage ```hcl diff --git a/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown index 2ae5f20232f7..e85b3cc31c8d 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown @@ -25,7 +25,7 @@ The following arguments are supported: * `region` - (Optional) The region you want to get the forwarding rules from. -These arguments must be set in either the provider or the resouce in order for the information to be queried. +These arguments must be set in either the provider or the resource in order for the information to be queried. ## Attributes Reference diff --git a/mmv1/third_party/terraform/website/docs/d/compute_network.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_network.html.markdown index 7ed18f65fe4a..dfe8b1f4cb35 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_network.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_network.html.markdown @@ -36,6 +36,8 @@ In addition to the arguments listed above, the following attributes are exported * `description` - Description of this network. +* `numeric_id` - The numeric unique identifier for the resource. + * `gateway_ipv4` - The IP address of the gateway. * `internal_ipv6_range` - The ula internal ipv6 range assigned to this network. diff --git a/mmv1/third_party/terraform/website/docs/d/compute_subnetwork.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_subnetwork.html.markdown index 3a2b43e35fdc..34e8b5f4f3a0 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_subnetwork.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_subnetwork.html.markdown @@ -40,6 +40,8 @@ In addition to the arguments listed above, the following attributes are exported * `network` - The network name or resource link to the parent network of this subnetwork. +* `subnetwork_id` - The numeric ID of the resource. + * `description` - Description of this subnetwork. * `ip_cidr_range` - The IP address range that machines in this diff --git a/mmv1/third_party/terraform/website/docs/d/service_account_id_token.html.markdown b/mmv1/third_party/terraform/website/docs/d/service_account_id_token.html.markdown index 733ba1cc4f62..845f692d3a60 100644 --- a/mmv1/third_party/terraform/website/docs/d/service_account_id_token.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/service_account_id_token.html.markdown @@ -25,7 +25,7 @@ For more information see ``` ## Example Usage - Service Account Impersonation. - `google_service_account_access_token` will use background impersonated credentials provided by [google_service_account_access_token](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/service_account_access_token). + `google_service_account_id_token` will use background impersonated credentials provided by [google_service_account_access_token](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/service_account_access_token). Note: to use the following, you must grant `target_service_account` the `roles/iam.serviceAccountTokenCreator` role on itself. diff --git a/mmv1/third_party/terraform/website/docs/d/service_account_key.html.markdown b/mmv1/third_party/terraform/website/docs/d/service_account_key.html.markdown index 9b72b713a7e2..8d87177f84d4 100644 --- a/mmv1/third_party/terraform/website/docs/d/service_account_key.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/service_account_key.html.markdown @@ -33,7 +33,7 @@ The following arguments are supported: `projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}/keys/{KEYID}`, where `{ACCOUNT}` is the email address or unique id of the service account. -* `project` - (Optional) The ID of the project that the service account will be created in. +* `project` - (Optional) The ID of the project that the service account is present in. Defaults to the provider project configuration. * `public_key_type` (Optional) The output format of the public key requested. TYPE_X509_PEM_FILE is the default output format. diff --git a/mmv1/third_party/terraform/website/docs/d/storage_bucket_object_content.html.markdown b/mmv1/third_party/terraform/website/docs/d/storage_bucket_object_content.html.markdown index 551f22540bbd..0d36abc9aca2 100644 --- a/mmv1/third_party/terraform/website/docs/d/storage_bucket_object_content.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/storage_bucket_object_content.html.markdown @@ -12,7 +12,7 @@ See [the official documentation](https://cloud.google.com/storage/docs/key-terms and [API](https://cloud.google.com/storage/docs/json_api/v1/objects). -~> **Warning:** The object content will be saved in the state, and visiable to everyone who has access to the state file. +~> **Warning:** The object content will be saved in the state, and visible to everyone who has access to the state file. ## Example Usage diff --git a/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_access_token.html.markdown b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_access_token.html.markdown new file mode 100644 index 000000000000..c6627448a818 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_access_token.html.markdown @@ -0,0 +1,74 @@ +--- +subcategory: "Cloud Platform" +description: |- + Produces access_token for impersonated service accounts +--- + +# google_service_account_access_token + +This ephemeral resource provides a google `oauth2` `access_token` for a different service account than the one initially running the script. + +For more information see +[the official documentation](https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials) as well as [iamcredentials.generateAccessToken()](https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/generateAccessToken) + +## Example Usage + +To allow `service_A` to impersonate `service_B`, grant the [Service Account Token Creator](https://cloud.google.com/iam/docs/service-accounts#the_service_account_token_creator_role) on B to A. + +In the IAM policy below, `service_A` is given the Token Creator role impersonate `service_B` + +```hcl +resource "google_service_account_iam_binding" "token-creator-iam" { + service_account_id = "projects/-/serviceAccounts/service_B@projectB.iam.gserviceaccount.com" + role = "roles/iam.serviceAccountTokenCreator" + members = [ + "serviceAccount:service_A@projectA.iam.gserviceaccount.com", + ] +} +``` + +Once the IAM permissions are set, you can apply the new token to a provider bootstrapped with it. Any resources that references the aliased provider will run as the new identity. + +In the example below, `google_project` will run as `service_B`. + +```hcl +provider "google" { +} + +ephemeral "google_service_account_access_token" "default" { + provider = google + target_service_account = "service_B@projectB.iam.gserviceaccount.com" + scopes = ["userinfo-email", "cloud-platform"] + lifetime = "300s" +} + +provider "google" { + alias = "impersonated" + access_token = ephemeral.google_service_account_access_token.default.access_token +} + +data "google_client_openid_userinfo" "me" { + provider = google.impersonated +} + +output "target-email" { + value = data.google_client_openid_userinfo.me.email +} +``` + +> *Note*: the generated token is non-refreshable and can have a maximum `lifetime` of `3600` seconds. + +## Argument Reference + +The following arguments are supported: + +* `target_service_account` (Required) - The service account _to_ impersonate (e.g. `service_B@your-project-id.iam.gserviceaccount.com`) +* `scopes` (Required) - The scopes the new credential should have (e.g. `["cloud-platform"]`) +* `delegates` (Optional) - Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. (e.g. `["projects/-/serviceAccounts/delegate-svc-account@project-id.iam.gserviceaccount.com"]`) +* `lifetime` (Optional) Lifetime of the impersonated token (defaults to its max: `3600s`). + +## Attributes Reference + +The following attribute is exported: + +* `access_token` - The `access_token` representing the new generated identity. diff --git a/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_id_token.html.markdown b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_id_token.html.markdown new file mode 100644 index 000000000000..0e9e15b5cf8a --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_id_token.html.markdown @@ -0,0 +1,72 @@ +--- +subcategory: "Cloud Platform" +description: |- + Produces OpenID Connect token for service accounts +--- + +# google_service_account_id_token + +This ephemeral resource provides a Google OpenID Connect (`oidc`) `id_token`. Tokens issued from this ephemeral resource are typically used to call external services that accept OIDC tokens for authentication (e.g. [Google Cloud Run](https://cloud.google.com/run/docs/authenticating/service-to-service)). + +For more information see +[OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html#IDToken). + +## Example Usage - ServiceAccount JSON credential file. + +-> **Note:** If you run this example configuration you will be able to see ephemeral.google_service_account_id_token.oidc in terraform plan and apply terminal output but you will not see it in state, as ephemeral resources are excluded from state. In future, when write-only attributes are added to resources in the Google provider, ephemeral resources such as google_service_account_id_token could be used to set field values when creating managed resources. + + `google_service_account_id_token` will use the configured [provider credentials](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#credentials-1) + + ```hcl + ephemeral "google_service_account_id_token" "oidc" { + target_audience = "https://foo.bar/" + } + ``` + +## Example Usage - Service Account Impersonation. + +-> **Note:** If you run this example configuration you will be able to see ephemeral.google_service_account_id_token.oidc in terraform plan and apply terminal output but you will not see it in state, as ephemeral resources are excluded from state. In future, when write-only attributes are added to resources in the Google provider, ephemeral resources such as google_service_account_id_token could be used to set field values when creating managed resources. + + Ephemeral resource `google_service_account_id_token` will use background impersonated credentials provided by [google_service_account_access_token](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/service_account_access_token). + + Note: to use the following, you must grant `target_service_account` the + `roles/iam.serviceAccountTokenCreator` role on itself. + + ```hcl + data "google_service_account_access_token" "impersonated" { + provider = google + target_service_account = "impersonated-account@project.iam.gserviceaccount.com" + delegates = [] + scopes = ["userinfo-email", "cloud-platform"] + lifetime = "300s" + } + + provider "google" { + alias = "impersonated" + access_token = data.google_service_account_access_token.impersonated.access_token + } + + ephemeral "google_service_account_id_token" "oidc" { + provider = google.impersonated + target_service_account = "impersonated-account@project.iam.gserviceaccount.com" + delegates = [] + include_email = true + target_audience = "https://foo.bar/" + } + + ``` + +## Argument Reference + +The following arguments are supported: + +* `target_audience` (Required) - The audience claim for the `id_token`. +* `target_service_account` (Optional) - The email of the service account being impersonated. Used only when using impersonation mode. +* `delegates` (Optional) - Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. Used only when using impersonation mode. +* `include_email` (Optional) Include the verified email in the claim. Used only when using impersonation mode. + +## Attributes Reference + +The following attribute is exported: + +* `id_token` - The `id_token` representing the new generated identity. diff --git a/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_jwt.html.markdown b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_jwt.html.markdown new file mode 100644 index 000000000000..ef0f90a609e1 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_jwt.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "Cloud Platform" +description: |- + Produces an arbitrary self-signed JWT for service accounts +--- + +# google_service_account_jwt + +This ephemeral resource provides a [self-signed JWT](https://cloud.google.com/iam/docs/create-short-lived-credentials-direct#sa-credentials-jwt). Tokens issued from this ephemeral resource are typically used to call external services that accept JWTs for authentication. + +## Example Usage + +-> **Note:** If you run this example configuration you will be able to see ephemeral.google_service_account_jwt.foo in terraform plan and apply terminal output but you will not see it in state, as ephemeral resources are excluded from state. In future, when write-only attributes are added to resources in the Google provider, ephemeral resources such as google_service_account_jwt could be used to set field values when creating managed resources. + +Note: in order to use the following, the caller must have _at least_ `roles/iam.serviceAccountTokenCreator` on the `target_service_account`. + +```hcl +ephemeral "google_service_account_jwt" "foo" { + target_service_account = "impersonated-account@project.iam.gserviceaccount.com" + + payload = jsonencode({ + foo: "bar", + sub: "subject", + }) + + expires_in = 60 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `target_service_account` (Required) - The email of the service account that will sign the JWT. +* `payload` (Required) - The JSON-encoded JWT claims set to include in the self-signed JWT. +* `expires_in` (Optional) - Number of seconds until the JWT expires. If set and non-zero an `exp` claim will be added to the payload derived from the current timestamp plus expires_in seconds. +* `delegates` (Optional) - Delegate chain of approvals needed to perform full impersonation. Specify the fully qualified service account name. + +## Attributes Reference + +The following attribute is exported: + +* `jwt` - The signed JWT containing the JWT Claims Set from the `payload`. diff --git a/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_key.html.markdown b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_key.html.markdown new file mode 100644 index 000000000000..43b2cef15938 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/ephemeral-resources/service_account_key.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "Cloud Platform" +description: |- + Get a Google Cloud Platform service account Public Key +--- + +# google_service_account_key + +Get an ephemeral service account public key. For more information, see [the official documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) and [API](https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys/get). + +## Example Usage + +-> **Note:** If you run this example configuration you will be able to see ephemeral.google_service_account_key.mykey in terraform plan and apply terminal output but you will not see it in state, as ephemeral resources are excluded from state. In future, when write-only attributes are added to resources in the Google provider, ephemeral resources such as google_service_account_key could be used to set field values when creating managed resources. + + +```hcl +resource "google_service_account" "myaccount" { + account_id = "dev-foo-account" +} + +resource "google_service_account_key" "mykey" { + service_account_id = google_service_account.myaccount.name +} + +ephemeral "google_service_account_key" "mykey" { + name = google_service_account_key.mykey.name + public_key_type = "TYPE_X509_PEM_FILE" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the service account key. This must have format + `projects/{PROJECT_ID}/serviceAccounts/{ACCOUNT}/keys/{KEYID}`, where `{ACCOUNT}` + is the email address or unique id of the service account. + +* `public_key_type` (Optional) The output format of the public key requested. TYPE_X509_PEM_FILE is the default output format. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `public_key` - The public key, base64 encoded diff --git a/mmv1/third_party/terraform/website/docs/guides/google-continuous-validation.html.markdown b/mmv1/third_party/terraform/website/docs/guides/google-continuous-validation.html.markdown index eadc69aacf7f..63ab063d58c0 100644 --- a/mmv1/third_party/terraform/website/docs/guides/google-continuous-validation.html.markdown +++ b/mmv1/third_party/terraform/website/docs/guides/google-continuous-validation.html.markdown @@ -1,18 +1,18 @@ --- -page_title: "Using Terraform Cloud's Continuous Validation feature with the Google Provider" +page_title: "Using HCP Terraform's Continuous Validation feature with the Google Provider" description: |- Continuous validation helps identify issues immediately and continuously instead of waiting until customers encounter problems. This guide shows how continuous validation can be used with the Google provider. --- -# Using Terraform Cloud's Continuous Validation feature with the Google Provider +# Using HCP Terraform's Continuous Validation feature with the Google Provider -The Continuous Validation feature in Terraform Cloud (TFC) allows users to make assertions about their infrastructure between applied runs. This helps users to identify issues at the time they first appear and avoid situations where a change is only identified during a future terraform plan/apply or once it causes a user-facing problem. +The Continuous Validation feature in HCP Terraform allows users to make assertions about their infrastructure between applied runs. This helps users to identify issues at the time they first appear and avoid situations where a change is only identified during a future terraform plan/apply or once it causes a user-facing problem. Users can add checks to their Terraform configuration using an HCL language feature called [check{} blocks](https://developer.hashicorp.com/terraform/language/checks). Check blocks contain assertions that are defined with a custom condition expression and an error message. When the condition expression evaluates to true the check passes, but when the expression evaluates to false Terraform will show a warning message that includes the user-defined error message. Custom conditions can be created using data from Terraform providers’ resources and data sources. Data can also be combined from multiple sources; for example, you can use checks to monitor expirable resources by comparing a resource’s expiration date attribute to the current time returned by Terraform’s built-in time functions. These include the [plantimestamp function](https://developer.hashicorp.com/terraform/language/functions/plantimestamp), which was added in Terraform 1.5. -For more information about continuous validation visit the [Workspace Health page in the Terraform Cloud documentation](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/health#continuous-validation). +For more information about continuous validation visit the [Workspace Health page in the HCP Terraform documentation](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/health#continuous-validation). Below, this guide shows examples of how data returned by the Google provider can be used to define checks in your Terraform configuration. In each example it is assumed that the Google provider is configured with a default project, region, and zone. @@ -24,7 +24,7 @@ VM instances provisioned using Compute Engine can pass through several states as The example below shows how a check block can be used to assert that a VM is in the running state. -You can force the check to fail in this example by provisioning the VM, manually stopping it in the Google Cloud console, and then triggering a health check in TFC. The check will fail and report that the VM is not running. +You can force the check to fail in this example by provisioning the VM, manually stopping it in the Google Cloud console, and then triggering a health check in HCP Terraform. The check will fail and report that the VM is not running. ```hcl data "google_compute_network" "default" { @@ -60,11 +60,11 @@ check "check_vm_status" { ## Example - Check if a certificate will expire within a certain timeframe (`google_privateca_certificate`) -Certificates can be provisioned using either the Certificate Manager, Certificate Authority Service (‘Private CA’), and Compute Engine APIs. In this example we provision a certificate via the Certificate Authority Service that has a user-supplied [lifetime argument](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/privateca_certificate#lifetime). After the lifetime duration passes the certificate is automatically deleted in GCP. By creating a check that asserts the certificate’s expiration date is more than 30 days away we can be notified by TFC health checks when the certificate is approaching expiration and needs manual intervention. +Certificates can be provisioned using either the Certificate Manager, Certificate Authority Service (‘Private CA’), and Compute Engine APIs. In this example we provision a certificate via the Certificate Authority Service that has a user-supplied [lifetime argument](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/privateca_certificate#lifetime). After the lifetime duration passes the certificate is automatically deleted in GCP. By creating a check that asserts the certificate’s expiration date is more than 30 days away we can be notified by HCP Terraform health checks when the certificate is approaching expiration and needs manual intervention. In the example below we provision a certificate with a lifetime of 30 days and 2 minutes (see `local.month_and_2min_in_second_duration`) and create a check that asserts certificates should be valid for the next month (see `local.month_in_hour_duration`). -We can see the check begin to fail by waiting 2 minutes after the certificate is provisioned and then triggering a health check in TFC. The check will fail and report that the certificate is due to expire in less than a month. +We can see the check begin to fail by waiting 2 minutes after the certificate is provisioned and then triggering a health check in HCP Terraform. The check will fail and report that the certificate is due to expire in less than a month. ```hcl locals { diff --git a/mmv1/third_party/terraform/website/docs/guides/using_ephemeral_resources.html.markdown b/mmv1/third_party/terraform/website/docs/guides/using_ephemeral_resources.html.markdown new file mode 100644 index 000000000000..dde065e489d0 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/guides/using_ephemeral_resources.html.markdown @@ -0,0 +1,108 @@ +--- +page_title: "Use ephemeral resources in the Google Cloud provider" +description: |- + How to use ephemeral resources in the Google Cloud provider +--- + +# Ephemeral Resources in the Google Cloud provider + +Ephemeral resources are Terraform resources that are essentially temporary. They allow users to access and use data in their configurations without that data being stored in Terraform state. + +Ephemeral resources are available in Terraform v1.10 and later. For more information, see the [official HashiCorp documentation for Ephemeral Resources](https://developer.hashicorp.com/terraform/language/resources/ephemeral). + +To mark the launch of the ephemeral resources feature, the Google Cloud provider has added four ephemeral resources: +- [`google_service_account_access_token`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_access_token) +- [`google_service_account_id_token`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_id_token) +- [`google_service_account_jwt`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_jwt) +- [`google_service_account_key`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_key) + +These are based on existing data sources already in the provider. In future you may wish to update your configurations to use these ephemeral versions, as they will allow you to avoid storing tokens and credentials values in your Terraform state. + +## Use the Google Cloud provider's new ephemeral resources + +Ephemeral resources are a source of ephemeral data, and they can be referenced in your configuration just like the attributes of resources and data sources. However, a field that references an ephemeral resource must be capable of handling ephemeral data. Due to this, resources in the Google Cloud provider will need to be updated so they include write-only attributes that are capable of using ephemeral data while not storing those values in the resource's state. + +Until then, ephemeral resources can only be used to pass values into the provider block, which is already capable of receiving ephemeral values. + +The following sections show two examples from the new ephemeral resources' documentation pages, which can be used to test out the ephemeral resources in their current form. + +### See how ephemeral resources behave during `terraform plan` and `terraform apply` + +The [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_key) for the `google_service_account_key` ephemeral resource has a simple example that you can use to view how ephemeral resources behave during plan and apply operations: + +```hcl +resource "google_service_account" "myaccount" { + account_id = "dev-foo-account" +} + +resource "google_service_account_key" "mykey" { + service_account_id = google_service_account.myaccount.name +} + +ephemeral "google_service_account_key" "mykey" { + name = google_service_account_key.mykey.name + public_key_type = "TYPE_X509_PEM_FILE" +} +``` + +During `terraform plan` you will see that the ephemeral resource is deferred, as it depends on other resources for its arguments: + +``` +ephemeral.google_service_account_key.mykey: Configuration unknown, deferring... + +Terraform used the selected providers to generate the +following execution plan. Resource actions are indicated +with the following symbols: + + create + +Terraform will perform the following actions: + + # google_service_account.myaccount will be created + + resource "google_service_account" "myaccount" { + ... +``` + +During `terrform apply` you will see the ephemeral resource is the final resource to be evaluated, because it depends on the two other resources, and the ephemeral resource is not reflected in the statistics about how many resources were created during the apply action: + +``` +ephemeral.google_service_account_key.mykey: Opening... +ephemeral.google_service_account_key.mykey: Opening complete after 1s +ephemeral.google_service_account_key.mykey: Closing... +ephemeral.google_service_account_key.mykey: Closing complete after 0s + +Apply complete! Resources: 2 added, 0 changed, 0 destroyed. +``` + +If you run the example using the local backend you can also inspect the state, where you will see that the ephemeral resource is not represented. + + +### Use ephemeral resources to configure the Google Cloud provider + +The [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/ephemeral-resources/service_account_access_token) for the `google_service_account_access_token` ephemeral resource demonstrates how it can be used to configure the provider. Check that ephemeral resource's documentation for details about the IAM permissions required for this example to work: + +```hcl +provider "google" { +} + + +ephemeral "google_service_account_access_token" "default" { + provider = google + target_service_account = "service_B@projectB.iam.gserviceaccount.com" + scopes = ["userinfo-email", "cloud-platform"] + lifetime = "300s" +} + +provider "google" { + alias = "impersonated" + access_token = ephemeral.google_service_account_access_token.default.access_token +} + +data "google_client_openid_userinfo" "me" { + provider = google.impersonated +} + +output "target-email" { + value = data.google_client_openid_userinfo.me.email +} +``` + diff --git a/mmv1/third_party/terraform/website/docs/guides/version_5_upgrade.html.markdown b/mmv1/third_party/terraform/website/docs/guides/version_5_upgrade.html.markdown index 078ef0f0323a..6fefdba30792 100644 --- a/mmv1/third_party/terraform/website/docs/guides/version_5_upgrade.html.markdown +++ b/mmv1/third_party/terraform/website/docs/guides/version_5_upgrade.html.markdown @@ -726,7 +726,7 @@ proposed value to configuration (below) or apply `lifecycle.ignore_changes` to t ## Resource: `google_dataflow_flex_template_job` -### Fields that are a part of the [environment block](https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.flexTemplates/launch#FlexTemplateRuntimeEnvironment) will be overriden to be sent via their fields even when supplied via parameters. +### Fields that are a part of the [environment block](https://cloud.google.com/dataflow/docs/reference/rest/v1b3/projects.locations.flexTemplates/launch#FlexTemplateRuntimeEnvironment) will be overridden to be sent via their fields even when supplied via parameters. Several fields within the `google_dataflow_flex_template_job` resource can be supplied through either the `parameters{}` block or a field on the resource object. Support for these fields on the resource object was added in the `4.66.0` release of the Google provider. That version introduced an issue where the values were being double-sent to the API due to being recorded in Terraform state in two places. To resolve this issue, these fields will be deduplicated and sent to the API through the resource object. 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 35740d97bcb9..8f560d4f662f 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 @@ -363,6 +363,35 @@ resource "google_composer_environment" "example" { } ``` +If you specify an existing network attachment that you also manage in Terraform, then Terraform will revert changes +to the attachment done by Cloud Composer when you apply configuration changes. As a result, the environment will no +longer use the attachment. To address this problem, make sure that Terraform ignores changes to the +`producer_accept_lists` parameter of the attachment, as follows: + +```hcl +resource "google_compute_network_attachment" "example" { + lifecycle { + ignore_changes = [producer_accept_lists] + } + + # ... other configuration parameters +} + +resource "google_composer_environment" "example" { + name = "example-environment" + region = "us-central1" + + config { + + node_config { + composer_network_attachment = google_compute_network_attachment.example.id + } + + # ... other configuration parameters + } +} +``` + ### With Software (Airflow) Config ```hcl @@ -1303,11 +1332,11 @@ The following arguments are supported: The configuration settings for software (Airflow) inside the environment. Structure is [documented below](#nested_software_config_c3). * `enable_private_environment` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) If true, a private Composer environment will be created. * `enable_private_builds_only` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) If true, builds performed during operations that install Python packages have only private connectivity to Google services. If false, the builds also have access to the internet. @@ -1377,7 +1406,7 @@ The following arguments are supported: network must also be provided and the subnetwork must belong to the enclosing environment's project and region. * `composer_network_attachment` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) PSC (Private Service Connect) Network entry point. Customers can pre-create the Network Attachment and point Cloud Composer environment to use. It is possible to share network attachment among many environments, provided enough IP addresses are available. @@ -1398,7 +1427,7 @@ The following arguments are supported: Cannot be updated. * `composer_internal_ipv4_cidr_block` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) /20 IPv4 cidr range that will be used by Composer internal components. Cannot be updated. @@ -1471,7 +1500,7 @@ The following arguments are supported: [documented below](#nested_cloud_data_lineage_integration_c3). * `web_server_plugins_mode` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) Web server plugins configuration. Can be either 'ENABLED' or 'DISABLED'. Defaults to 'ENABLED'. The `cloud_data_lineage_integration` block supports: @@ -1523,7 +1552,7 @@ The `workloads_config` block supports: Configuration for resources used by Airflow workers. * `dag_processor` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html), Cloud Composer 3 only) + (Optional, Cloud Composer 3 only) Configuration for resources used by DAG processor. The `scheduler` block supports: diff --git a/mmv1/third_party/terraform/website/docs/r/composer_user_workloads_secret.html.markdown b/mmv1/third_party/terraform/website/docs/r/composer_user_workloads_secret.html.markdown index 797798867148..e07d8293d763 100644 --- a/mmv1/third_party/terraform/website/docs/r/composer_user_workloads_secret.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/composer_user_workloads_secret.html.markdown @@ -6,9 +6,6 @@ description: |- # google_composer_user_workloads_secret -~> **Warning:** These resources are in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. - User workloads Secret used by Airflow tasks that run with Kubernetes Executor or KubernetesPodOperator. Intended for Composer 3 Environments. diff --git a/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown index 83ea8d38944b..acd46bad2410 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown @@ -326,10 +326,12 @@ is desired, you will need to modify your state file manually using * `enable_confidential_compute` - (Optional) Whether this disk is using confidential compute mode. Note: Only supported on hyperdisk skus, disk_encryption_key is required when setting to true. -* `storage_pool` - (Optional) The URL of the storage pool in which the new disk is created. +* `storage_pool` - (Optional) The URL or the name of the storage pool in which the new disk is created. For example: * https://www.googleapis.com/compute/v1/projects/{project}/zones/{zone}/storagePools/{storagePool} * /projects/{project}/zones/{zone}/storagePools/{storagePool} + * /zones/{zone}/storagePools/{storagePool} + * /{storagePool} The `scratch_disk` block supports: @@ -399,7 +401,7 @@ is desired, you will need to modify your state file manually using * `network_attachment` - (Optional) [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html) The URL of the network attachment that this interface should connect to in the following format: `projects/{projectNumber}/regions/{region_name}/networkAttachments/{network_attachment_name}`. -* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6, IPV6_ONLY or IPV4_ONLY. If not specified, IPV4_ONLY will be used. +* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6 or IPV4_ONLY. If not specified, IPV4_ONLY will be used. * `ipv6_access_config` - (Optional) An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig @@ -575,6 +577,8 @@ specified, then this instance will have no external IPv6 Internet access. Struct * `performance_monitoring_unit` - (Optional) [The PMU](https://cloud.google.com/compute/docs/pmu-overview) is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are `STANDARD`, `ENHANCED`, and `ARCHITECTURAL`. +* `enable_uefi_networking` - (Optional) Whether to enable UEFI networking for instance creation. + The `reservation_affinity` block supports: * `type` - (Required) The type of reservation from which this instance can consume resources. diff --git a/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown index ef900aff1539..88a604fa44a7 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown @@ -563,7 +563,7 @@ The following arguments are supported: * `nic_type` - (Optional) The type of vNIC to be used on this interface. Possible values: GVNIC, VIRTIO_NET. In the beta provider the additional values of MRDMA and IRDMA are supported. -* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6, IPV6_ONLY or IPV4_ONLY. If not specified, IPV4_ONLY will be used. +* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6 or IPV4_ONLY. If not specified, IPV4_ONLY will be used. * `ipv6_access_config` - (Optional) An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig @@ -732,6 +732,8 @@ The `specific_reservation` block supports: * `performance_monitoring_unit` - (Optional) [The PMU](https://cloud.google.com/compute/docs/pmu-overview) is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are `STANDARD`, `ENHANCED`, and `ARCHITECTURAL`. +* `enable_uefi_networking` - (Optional) Whether to enable UEFI networking for instance creation. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown index 12ba8874792c..9377858dd044 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown @@ -529,7 +529,7 @@ The following arguments are supported: * `nic_type` - (Optional) The type of vNIC to be used on this interface. Possible values: GVNIC, VIRTIO_NET. In the beta provider the additional values of MRDMA and IRDMA are supported. -* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6, IPV6_ONLY or IPV4_ONLY. If not specified, IPV4_ONLY will be used. +* `stack_type` - (Optional) The stack type for this network interface to identify whether the IPv6 feature is enabled or not. Values are IPV4_IPV6 or IPV4_ONLY. If not specified, IPV4_ONLY will be used. * `ipv6_access_config` - (Optional) An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig @@ -692,6 +692,8 @@ The `specific_reservation` block supports: * `performance_monitoring_unit` - (Optional) [The PMU](https://cloud.google.com/compute/docs/pmu-overview) is a hardware component within the CPU core that monitors how the processor runs code. Valid values for the level of PMU are `STANDARD`, `ENHANCED`, and `ARCHITECTURAL`. +* `enable_uefi_networking` - (Optional) Whether to enable UEFI networking for instance creation. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are diff --git a/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown index 00c73a5450a9..9b1aaa175604 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown @@ -430,6 +430,39 @@ The following arguments are supported: * `STANDARD` - opaque rules. (default) * `PREMIUM` - transparent rules. +* `threshold_configs` - (Optional) Configuration options for layer7 adaptive protection for various customizable thresholds. Structure is [documented below](#nested_threshold_configs). + +The `threshold_configs` block supports: + +* `name` - The name of config. The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the security policy. + +* `auto_deploy_load_threshold` - (Optional) Load threshold above which Adaptive Protection automatically deploy threshold based on the backend load threshold and detect a new rule during an alerted attack. + +* `auto_deploy_confidence_threshold` - (Optional) Confidence threshold above which Adaptive Protection's auto-deploy takes actions. + +* `auto_deploy_impacted_baseline_threshold` - (Optional) Impacted baseline threshold below which Adaptive Protection's auto-deploy takes actions. + +* `auto_deploy_expiration_sec` - (Optional) Duration over which Adaptive Protection's auto-deployed actions last. + +* `detection_load_threshold` - (Optional) Detection threshold based on the backend service's load. + +* `detection_absolute_qps` - (Optional) Detection threshold based on absolute QPS. + +* `detection_relative_to_baseline_qps` - (Optional) Detection threshold based on QPS relative to the average of baseline traffic. + +* `traffic_granularity_configs` - (Optional) Configuration options for enabling Adaptive Protection to work on the specified service granularity. Structure is [documented below](#nested_traffic_granularity_configs). + +The `traffic_granularity_configs` block supports: + +* `type` - The type of this configuration, a granular traffic unit can be one of the following: + * `HTTP_HEADER_HOST` + * `HTTP_PATH` + +* `value` - (Optional) Requests that match this value constitute a granular traffic unit. + +* `enable_each_unique_value` - (Optional) If enabled, traffic matching each unique value for the specified type constitutes a separate traffic unit. It can only be set to true if value is empty. + + The `auto_deploy_config` block supports: * `load_threshold` - (Optional) Identifies new attackers only when the load to the backend service that is under attack exceeds this threshold. 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 368c1b2a441d..b69680f24eca 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 @@ -121,9 +121,10 @@ locations. In contrast, in a regional cluster, cluster master nodes are present in multiple zones in the region. For that reason, regional clusters should be preferred. -* `deletion_protection` - (Optional) Whether or not to allow Terraform to destroy -the cluster. Unless this field is set to false in Terraform state, a -`terraform destroy` or `terraform apply` that would delete the cluster will fail. +* `deletion_protection` - (Optional) Whether Terraform will be prevented from +destroying the cluster. Deleting this cluster via `terraform destroy` or +`terraform apply` will only succeed if this field is `false` in the Terraform +state. * `addons_config` - (Optional) The configuration for addons supported by GKE. Structure is [documented below](#nested_addons_config). @@ -371,7 +372,7 @@ subnetwork in which the cluster's instances are launched. * `enable_multi_networking` - (Optional) Whether multi-networking is enabled for this cluster. -* `enable_fqdn_network_policy` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) +* `enable_fqdn_network_policy` - (Optional) Whether FQDN Network Policy is enabled on this cluster. Users who enable this feature for existing Standard clusters must restart the GKE Dataplane V2 `anetd` DaemonSet after enabling it. See the [Enable FQDN Network Policy in an existing cluster](https://cloud.google.com/kubernetes-engine/docs/how-to/fqdn-network-policies#enable_fqdn_network_policy_in_an_existing_cluster) for more information. * `private_ipv6_google_access` - (Optional) @@ -404,6 +405,10 @@ Fleet configuration for the cluster. Structure is [documented below](#nested_fle * `workload_alts_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Configuration for [direct-path (via ALTS) with workload identity.](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters#workloadaltsconfig). Structure is [documented below](#nested_workload_alts_config). +* `enterprise_config` - (Optional) + Configuration for [Enterprise edition].(https://cloud.google.com/kubernetes-engine/enterprise/docs/concepts/gke-editions). Structure is [documented below](#nested_enterprise_config). + + The `default_snat_status` block supports * `disabled` - (Required) Whether the cluster disables default in-node sNAT rules. In-node sNAT rules will be disabled when defaultSnatStatus is disabled.When disabled is set to false, default IP masquerade rules will be applied to the nodes to prevent sNAT on cluster internal traffic @@ -596,7 +601,7 @@ as "Intel Haswell" or "Intel Sandy Bridge". * `disk_size` - (Optional) Size of the disk attached to each node, specified in GB. The smallest allowed disk size is 10GB. Defaults to `100` -* `disk_type` - (Optional) Type of the disk attached to each node (e.g. 'pd-standard', 'pd-ssd' or 'pd-balanced'). Defaults to `pd-standard` +* `disk_type` - (Optional) Type of the disk attached to each node (e.g. 'pd-standard', 'pd-ssd', 'pd-balanced', or 'hyperdisk-balanced'). Defaults to `hyperdisk-balanced` if `hyperdisk-balanced` is supported and `pd-balanced` is not supported for the machine type; otherwise defaults to `pd-balanced`. * `image_type` - (Optional) The default image type used by NAP once a new node pool is being created. Please note that according to the [official documentation](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-provisioning#default-image-type) the value must be one of the [COS_CONTAINERD, COS, UBUNTU_CONTAINERD, UBUNTU]. __NOTE__ : COS AND UBUNTU are deprecated as of `GKE 1.24` @@ -1110,6 +1115,8 @@ Structure is [documented below](#nested_node_kubelet_config). * `network_tags` (Optional) - The network tag config for the cluster's automatically provisioned node pools. Structure is [documented below](#nested_network_tags). +* `linux_node_config` (Optional) - Linux system configuration for the cluster's automatically provisioned node pools. Only `cgroup_mode` field is supported in `node_pool_auto_config`. Structure is [documented below](#nested_linux_node_config). + The `node_kubelet_config` block supports: * `insecure_kubelet_readonly_port_enabled` - (Optional) Controls whether the kubelet read-only port is enabled. It is strongly recommended to set this to `FALSE`. Possible values: `TRUE`, `FALSE`. @@ -1430,6 +1437,11 @@ linux_node_config { * `enable_alts` - (Required) Whether the alts handshaker should be enabled or not for direct-path. Requires Workload Identity ([workloadPool]((#nested_workload_identity_config)) must be non-empty). +The `enterprise_config` block supports: + +* `desired_tier` - (Optional) Sets the tier of the cluster. Available options include `STANDARD` and `ENTERPRISE`. + + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are @@ -1479,6 +1491,8 @@ exported: * `fleet.0.membership_location` - The location of the fleet membership, extracted from `fleet.0.membership`. You can use this field to configure `membership_location` under [google_gkehub_feature_membership](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership). +* `enterprise_config.0.cluster_tier` - The effective tier of the cluster. + ## Timeouts This resource provides the following diff --git a/mmv1/third_party/terraform/website/docs/r/dataproc_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/dataproc_cluster.html.markdown index 926e19d6d598..28e215e4eba1 100644 --- a/mmv1/third_party/terraform/website/docs/r/dataproc_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/dataproc_cluster.html.markdown @@ -214,7 +214,7 @@ resource "google_dataproc_cluster" "accelerated_cluster" { kubernetes_software_config { component_version = { - "SPARK" : "3.1-dataproc-7" + "SPARK" : "3.5-dataproc-17" } properties = { @@ -448,6 +448,9 @@ resource "google_dataproc_cluster" "accelerated_cluster" { * `node_group_affinity` - (Optional) Node Group Affinity for sole-tenant clusters. * `node_group_uri` - (Required) The URI of a sole-tenant node group resource that the cluster will be created on. +* `confidential_instance_config` - (Optional) Confidential Instance Config for clusters using [Confidential VMs](https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/confidential-compute) + * `enable_confidential_compute` - (Optional) Defines whether the instance should have confidential compute enabled. + * `shielded_instance_config` (Optional) Shielded Instance Config for clusters using [Compute Engine Shielded VMs](https://cloud.google.com/security/shielded-cloud/shielded-vm). - - - diff --git a/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown b/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown index 10642b263911..4b2eb0f8b29c 100644 --- a/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/gke_hub_feature_membership.html.markdown @@ -418,11 +418,15 @@ The following arguments are supported: * `prevent_drift` - (Optional) - Supported from Config Sync versions 1.10.0 onwards. Set to true to enable the Config Sync admission webhook to prevent drifts. If set to "false", disables the Config Sync admission webhook and does not prevent drifts. + Supported from Config Sync versions 1.10.0 onwards. Set to `true` to enable the Config Sync admission webhook to prevent drifts. If set to `false`, disables the Config Sync admission webhook and does not prevent drifts. * `source_format` - (Optional) Specifies whether the Config Sync Repo is in "hierarchical" or "unstructured" mode. + +* `stop_syncing` - + (Optional) + Set to `true` to stop syncing configurations for a single cluster. This field is only available on clusters using Config Sync [auto-upgrades](http://cloud/kubernetes-engine/enterprise/config-sync/docs/how-to/upgrade-config-sync#auto-upgrade-config) or on Config Sync version 1.20.0 or later. Defaults: `false`. The `git` block supports: diff --git a/mmv1/third_party/terraform/website/docs/r/usage_export_bucket.html.markdown b/mmv1/third_party/terraform/website/docs/r/project_usage_export_bucket.html.markdown similarity index 100% rename from mmv1/third_party/terraform/website/docs/r/usage_export_bucket.html.markdown rename to mmv1/third_party/terraform/website/docs/r/project_usage_export_bucket.html.markdown 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 5c70a7a4c1a2..edcfd45446ee 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 @@ -240,8 +240,8 @@ The following arguments are supported: * `database_version` - (Required) The MySQL, PostgreSQL or SQL Server version to use. Supported values include `MYSQL_5_6`, `MYSQL_5_7`, `MYSQL_8_0`, `POSTGRES_9_6`,`POSTGRES_10`, `POSTGRES_11`, -`POSTGRES_12`, `POSTGRES_13`, `POSTGRES_14`, `POSTGRES_15`, `SQLSERVER_2017_STANDARD`, -`SQLSERVER_2017_ENTERPRISE`, `SQLSERVER_2017_EXPRESS`, `SQLSERVER_2017_WEB`. +`POSTGRES_12`, `POSTGRES_13`, `POSTGRES_14`, `POSTGRES_15`, `POSTGRES_16`, `POSTGRES_17`, +`SQLSERVER_2017_STANDARD`, `SQLSERVER_2017_ENTERPRISE`, `SQLSERVER_2017_EXPRESS`, `SQLSERVER_2017_WEB`. `SQLSERVER_2019_STANDARD`, `SQLSERVER_2019_ENTERPRISE`, `SQLSERVER_2019_EXPRESS`, `SQLSERVER_2019_WEB`. [Database Version Policies](https://cloud.google.com/sql/docs/db-versions) @@ -262,7 +262,7 @@ includes an up-to-date reference of supported versions. is not provided, the provider project is used. * `replica_configuration` - (Optional) The configuration for replication. The - configuration is detailed below. + configuration is detailed below. * `replica_names` - (Optional, Computed) List of replica names. Can be updated. @@ -316,7 +316,7 @@ The `settings` block supports: * `collation` - (Optional) The name of server instance collation. -* `connector_enforcement` - (Optional) Enables the enforcement of Cloud SQL Auth Proxy or Cloud SQL connectors for all the connections. If enabled, all the direct connections are rejected. +* `connector_enforcement` - (Optional) Control the enforcement of Cloud SQL Auth Proxy or Cloud SQL connectors for all the connections, can be `REQUIRED` or `NOT_REQUIRED`. If enabled, all the direct connections are rejected. * `deletion_protection_enabled` - (Optional) Enables deletion protection of an instance at the GCP level. Enabling this protection will guard against accidental deletion across all surfaces (API, gcloud, Cloud Console and Terraform) by enabling the [GCP Cloud SQL instance deletion protection](https://cloud.google.com/sql/docs/postgres/deletion-protection). Terraform provider support was introduced in version 4.48.0. Defaults to `false`. @@ -687,4 +687,4 @@ $ terraform import google_sql_database_instance.default {{name}} ~> **NOTE:** Some fields (such as `replica_configuration`) won't show a diff if they are unset in config and set on the server. When importing, double-check that your config has all the fields set that you expect- just seeing -no diff isn't sufficient to know that your config could reproduce the imported resource. \ No newline at end of file +no diff isn't sufficient to know that your config could reproduce the imported resource. diff --git a/mmv1/third_party/terraform/website/docs/r/storage_transfer_job.html.markdown b/mmv1/third_party/terraform/website/docs/r/storage_transfer_job.html.markdown index 5a338c487fcd..15daf0dd51b0 100644 --- a/mmv1/third_party/terraform/website/docs/r/storage_transfer_job.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/storage_transfer_job.html.markdown @@ -155,6 +155,8 @@ The following arguments are supported: * `azure_blob_storage_data_source` - (Optional) An Azure Blob Storage data source. Structure [documented below](#nested_azure_blob_storage_data_source). +* `hdfs_data_source` - (Optional) An HDFS data source. Structure [documented below](#nested_hdfs_data_source). + The `schedule` block supports: * `schedule_start_date` - (Required) The first day the recurring transfer is scheduled to run. If `schedule_start_date` is in the past, the transfer will run for the first time on the following day. Structure [documented below](#nested_schedule_start_end_date). @@ -219,6 +221,10 @@ A duration in seconds with up to nine fractional digits, terminated by 's'. Exam * `root_directory` - (Required) Root directory path to the filesystem. +The `hdfs_data_source` block supports: + +* `path` - (Required) Root directory path to the filesystem. + The `aws_s3_data_source` block supports: * `bucket_name` - (Required) S3 Bucket name. diff --git a/mmv1/third_party/tgc/tests/data/example_container_cluster.json b/mmv1/third_party/tgc/tests/data/example_container_cluster.json index c39ccef2fddd..23fabbc6e4ac 100644 --- a/mmv1/third_party/tgc/tests/data/example_container_cluster.json +++ b/mmv1/third_party/tgc/tests/data/example_container_cluster.json @@ -46,7 +46,8 @@ "oauthScopes": [ "https://www.googleapis.com/auth/cloud-platform" ], - "preemptible": true + "preemptible": true, + "serviceAccount": "service-account-cc@{{.Provider.project}}.iam.gserviceaccount.com" }, "location": "us-central1", "management": { diff --git a/mmv1/third_party/tgc/tests/data/example_google_composer_environment.json b/mmv1/third_party/tgc/tests/data/example_google_composer_environment.json index 0a5e6f71a28f..3f04a93dbfe6 100644 --- a/mmv1/third_party/tgc/tests/data/example_google_composer_environment.json +++ b/mmv1/third_party/tgc/tests/data/example_google_composer_environment.json @@ -7,7 +7,7 @@ { "role": "roles/composer.worker", "members": [ - "" + "serviceAccount:composer-new-account@{{.Provider.project}}.iam.gserviceaccount.com" ] } ] diff --git a/tools/issue-labeler/cmd/backfill_issue_labels.go b/tools/issue-labeler/cmd/backfill_issue_labels.go new file mode 100644 index 000000000000..c353b29e579c --- /dev/null +++ b/tools/issue-labeler/cmd/backfill_issue_labels.go @@ -0,0 +1,70 @@ +/* +* Copyright 2024 Google LLC. All Rights Reserved. +* +* 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. + */ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler/labeler" +) + +var ( + // used for flags + backfillSince string + backfillDryRun bool +) + +var backfillIssueLabels = &cobra.Command{ + Use: "backfill-issue-labels [--dry-run] [--since=1973-01-01]", + Short: "Backfills labels on old issues", + Long: "Backfills labels on old issues", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + // For now actual usage is handled inside UpdateIssues. This is just a new quick check. + _, ok := os.LookupEnv("GITHUB_TOKEN") + if !ok { + return fmt.Errorf("did not provide GITHUB_TOKEN environment variable") + } + return execBackfillIssueLabels() + }, +} + +func execBackfillIssueLabels() error { + regexpLabels, err := labeler.BuildRegexLabels(labeler.EnrolledTeamsYaml) + if err != nil { + return fmt.Errorf("building regex labels: %w", err) + } + repository := "hashicorp/terraform-provider-google" + issues, err := labeler.GetIssues(repository, backfillSince) + if err != nil { + return fmt.Errorf("getting github issues: %w", err) + } + issueUpdates := labeler.ComputeIssueUpdates(issues, regexpLabels) + err = labeler.UpdateIssues(repository, issueUpdates, backfillDryRun) + if err != nil { + return fmt.Errorf("updating github issues: %w", err) + } + return nil +} + +func init() { + rootCmd.AddCommand(backfillIssueLabels) + backfillIssueLabels.Flags().BoolVar(&backfillDryRun, "dry-run", false, "Only log write actions instead of updating issues") + backfillIssueLabels.Flags().StringVar(&backfillSince, "since", "1973-01-01", "Only apply labels to issues filed after given date") +} diff --git a/tools/issue-labeler/cmd/compute_new_labels.go b/tools/issue-labeler/cmd/compute_new_labels.go new file mode 100644 index 000000000000..22b5326fae95 --- /dev/null +++ b/tools/issue-labeler/cmd/compute_new_labels.go @@ -0,0 +1,58 @@ +/* +* Copyright 2024 Google LLC. All Rights Reserved. +* +* 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. + */ +package cmd + +import ( + "fmt" + "os" + "sort" + "strings" + + "github.com/spf13/cobra" + + "github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler/labeler" +) + +var computeNewLabels = &cobra.Command{ + Use: "compute-new-labels", + Short: "Computes labels that should be added to an issue based on its body", + Long: "Computes labels that should be added to an issue based on its body", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return execComputeNewLabels() + }, +} + +func execComputeNewLabels() error { + regexpLabels, err := labeler.BuildRegexLabels(labeler.EnrolledTeamsYaml) + if err != nil { + return fmt.Errorf("building regex labels: %w", err) + } + issueBody := os.Getenv("ISSUE_BODY") + affectedResources := labeler.ExtractAffectedResources(issueBody) + labels := labeler.ComputeLabels(affectedResources, regexpLabels) + + if len(labels) > 0 { + labels = append(labels, "forward/review") + sort.Strings(labels) + fmt.Println(`["` + strings.Join(labels, `", "`) + `"]`) + } + return nil +} + +func init() { + rootCmd.AddCommand(computeNewLabels) +} diff --git a/tools/issue-labeler/cmd/root.go b/tools/issue-labeler/cmd/root.go new file mode 100644 index 000000000000..5c035d9f2f32 --- /dev/null +++ b/tools/issue-labeler/cmd/root.go @@ -0,0 +1,41 @@ +/* +* Copyright 2024 Google LLC. All Rights Reserved. +* +* 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. + */ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands + +var rootCmd = &cobra.Command{ + Use: "issue-labeler", + Short: "Tool for interacting with issue labels (specifically for services)", + Long: `Tool for interacting with issue labels (specifically for services)`, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/tools/issue-labeler/go.mod b/tools/issue-labeler/go.mod index bdd9a278d9a1..7c7ed5edc1f2 100644 --- a/tools/issue-labeler/go.mod +++ b/tools/issue-labeler/go.mod @@ -8,4 +8,9 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) -require gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +) diff --git a/tools/issue-labeler/go.sum b/tools/issue-labeler/go.sum index a308adc5aa29..40345351b651 100644 --- a/tools/issue-labeler/go.sum +++ b/tools/issue-labeler/go.sum @@ -1,10 +1,18 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= golang.org/x/exp v0.0.0-20230810033253-352e893a4cad h1:g0bG7Z4uG+OgH2QDODnjp6ggkk1bJDsINcuWmJN1iJU= golang.org/x/exp v0.0.0-20230810033253-352e893a4cad/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -12,3 +20,4 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/issue-labeler/labeler/backfill.go b/tools/issue-labeler/labeler/backfill.go index 89eed2d58077..21a58df4baa6 100644 --- a/tools/issue-labeler/labeler/backfill.go +++ b/tools/issue-labeler/labeler/backfill.go @@ -3,6 +3,7 @@ package labeler import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -37,7 +38,7 @@ type IssueUpdateBody struct { Labels []string `json:"labels"` } -func GetIssues(repository, since string) []Issue { +func GetIssues(repository, since string) ([]Issue, error) { client := &http.Client{} done := false page := 1 @@ -46,19 +47,19 @@ func GetIssues(repository, since string) []Issue { url := fmt.Sprintf("https://api.github.com/repos/%s/issues?since=%s&per_page=100&page=%d", repository, since, page) req, err := http.NewRequest("GET", url, nil) if err != nil { - glog.Exitf("Error creating request: %v", err) + return nil, fmt.Errorf("creating request: %w", err) } req.Header.Add("Accept", "application/vnd.github+json") req.Header.Add("Authorization", "Bearer "+os.Getenv("GITHUB_TOKEN")) req.Header.Add("X-GitHub-Api-Version", "2022-11-28") resp, err := client.Do(req) if err != nil { - glog.Exitf("Error listing issues: %v", err) + return nil, fmt.Errorf("listing issues: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - glog.Exitf("Error reading response body: %v", err) + return nil, fmt.Errorf("reading response body: %v", err) } var newIssues []Issue json.Unmarshal(body, &newIssues) @@ -66,7 +67,7 @@ func GetIssues(repository, since string) []Issue { var err ErrorResponse json.Unmarshal(body, &err) if err.Message == "Bad credentials" { - glog.Exitf("Error from API: Bad credentials") + return nil, errors.New("Error from API: Bad credentials") } glog.Infof("API returned message: %s", err.Message) done = true @@ -75,7 +76,7 @@ func GetIssues(repository, since string) []Issue { page++ } } - return issues + return issues, nil } func ComputeIssueUpdates(issues []Issue, regexpLabels []RegexpLabel) []IssueUpdate { @@ -134,52 +135,60 @@ func ComputeIssueUpdates(issues []Issue, regexpLabels []RegexpLabel) []IssueUpda return issueUpdates } -func UpdateIssues(repository string, issueUpdates []IssueUpdate, dryRun bool) { +func UpdateIssues(repository string, issueUpdates []IssueUpdate, dryRun bool) error { client := &http.Client{} + failed := 0 for _, issueUpdate := range issueUpdates { url := fmt.Sprintf("https://api.github.com/repos/%s/issues/%d", repository, issueUpdate.Number) updateBody := IssueUpdateBody{Labels: issueUpdate.Labels} body, err := json.Marshal(updateBody) if err != nil { - glog.Errorf("Error marshalling json: %v", err) - continue + return fmt.Errorf("marshalling json: %w", err) } buf := bytes.NewReader(body) req, err := http.NewRequest("PATCH", url, buf) req.Header.Add("Authorization", "Bearer "+os.Getenv("GITHUB_TOKEN")) req.Header.Add("X-GitHub-Api-Version", "2022-11-28") if err != nil { - glog.Errorf("Error creating request: %v", err) - continue + return fmt.Errorf("creating request: %w", err) } fmt.Printf("Existing labels: %v\n", issueUpdate.OldLabels) fmt.Printf("New labels: %v\n", issueUpdate.Labels) fmt.Printf("%s %s (https://github.com/%s/issues/%d)\n", req.Method, req.URL, repository, issueUpdate.Number) + + // Pretty-print the body for debugging b, err := json.MarshalIndent(updateBody, "", " ") if err != nil { - glog.Errorf("Error marshalling json: %v", err) - continue + return fmt.Errorf("Error marshalling json: %w", err) } fmt.Println(string(b)) + if !dryRun { resp, err := client.Do(req) if err != nil { glog.Errorf("Error updating issue: %v", err) + failed += 1 continue } body, err := io.ReadAll(resp.Body) if err != nil { glog.Errorf("Error reading response body: %v", err) + failed += 1 continue } var errResp ErrorResponse json.Unmarshal(body, &errResp) if errResp.Message != "" { fmt.Printf("API error: %s", errResp.Message) + failed += 1 continue } } fmt.Printf("GitHub Issue %s %d updated successfully", repository, issueUpdate.Number) } + if failed > 0 { + return fmt.Errorf("failed to update %d / %d issues", failed, len(issueUpdates)) + } + return nil } diff --git a/tools/issue-labeler/labeler/enrolled_teams.yml b/tools/issue-labeler/labeler/enrolled_teams.yml index 58ef76ea2edd..ea72f5e0b956 100755 --- a/tools/issue-labeler/labeler/enrolled_teams.yml +++ b/tools/issue-labeler/labeler/enrolled_teams.yml @@ -87,6 +87,10 @@ service/certificatemanager: - google_compute_managed_ssl_certificate - google_compute_region_ssl_certificate - google_compute_ssl_certificate +service/chronicle: + team: chronicle-terraform + resources: + - google_chronicle_.* service/cloud-dns: resources: - google_dns_.* @@ -211,6 +215,7 @@ service/compute-managed: - google_compute_per_instance_config.* - google_compute_region_per_instance_config.* - google_compute_resize_request.* + - google_compute_region_resize_request.* service/compute-nat: resources: - google_compute_router_nat.* @@ -313,6 +318,9 @@ service/dataproc: - google_dataproc_job.* - google_dataproc_workflow_template - google_dataproc_batch +service/dataprocgdc: + resources: + - google_dataproc_gdc_.* service/datastream: resources: - google_datastream_.* @@ -373,6 +381,9 @@ service/firestore-dataplane: - google_firestore_field - google_firestore_index - google_firestore_ttl +service/gemini: + resources: + - google_gemini_.* service/gkebackup: resources: - google_gke_backup_.* @@ -397,6 +408,8 @@ service/iam-core: - google_iam_deny_policy - google_iam_policy - google_iam_role + - google_iam_.*_policy_binding + - google_iam_principal_access_boundary_policy - google_iam_testable_permissions service/iam-serviceaccount: resources: @@ -491,6 +504,9 @@ service/network-security-distributed-firewall: - google_compute_network_firewall_policy.* - google_compute_organization_security_policy.* - google_compute_region_network_firewall_policy.* +service/networkconnectivity-private-range: + resources: + - google_network_connectivity_internal_range service/networkconnectivity-serviceautomation: resources: - google_network_connectivity_service_.* @@ -503,6 +519,10 @@ service/networksecurity-swp: - google_network_security_gateway_security_policy_rule - google_network_security_url_lists - google_network_security_tls_inspection_policy +service/networksecurityintegrations: + resources: + - google_network_security_mirroring.* + - google_network_security_intercept.* service/networkservices-media-cdn: resources: - google_network_services_edge_cache_.* diff --git a/tools/issue-labeler/labeler/labels.go b/tools/issue-labeler/labeler/labels.go index d702b081dd65..1862d6c44676 100644 --- a/tools/issue-labeler/labeler/labels.go +++ b/tools/issue-labeler/labeler/labels.go @@ -34,7 +34,7 @@ func BuildRegexLabels(teamsYaml []byte) ([]RegexpLabel, error) { enrolledTeams := make(map[string]LabelData) regexpLabels := []RegexpLabel{} if err := yaml.Unmarshal(teamsYaml, &enrolledTeams); err != nil { - return regexpLabels, fmt.Errorf("Error unmarshalling enrolled teams yaml: %w", err) + return regexpLabels, fmt.Errorf("unmarshalling enrolled teams yaml: %w", err) } for label, data := range enrolledTeams { diff --git a/tools/issue-labeler/labeler/labels_test.go b/tools/issue-labeler/labeler/labels_test.go index 7161969dd8e9..dc02d198e884 100644 --- a/tools/issue-labeler/labeler/labels_test.go +++ b/tools/issue-labeler/labeler/labels_test.go @@ -14,7 +14,7 @@ func TestExtractAffectedResources(t *testing.T) { expectedResources []string }{ "2023 bug": { - body: "\r\n\r\n### Community Note\r\n\r\n* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request.\r\n* Please do not leave _+1_ or _me too_ comments, they generate extra noise for issue followers and do not help prioritize the request.\r\n* If you are interested in working on this issue or have submitted a pull request, please leave a comment.\r\n* If an issue is assigned to the `modular-magician` user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to `hashibot`, a community member has claimed the issue already.\r\n\r\n\r\n\r\n### Terraform Version\r\n\r\n\r\nTerraform v1.3.7\r\non linux_amd64\r\nprovider registry.terraform.io/hashicorp/google v4.48.0\r\n\r\n### Affected Resource(s)\r\n\r\n\r\n\r\n* google_container_node_pool\r\n* google_container_cluster\r\n\r\n### Terraform Configuration Files\r\n\r\n\r\n\r\n```tf\r\nnode_config {\r\n tags = null\r\n}\r\n```\r\n### Expected Behavior\r\n\r\nIn above code, if there already exists a list of tags defined in the `node_config` block then I would expect TF to ignore this tags field and leave them as they are\r\n\r\n### Actual Behavior\r\n\r\nTF sets the tags to an emtpy list, [], thus removing existing tags\r\n\r\n### Steps to Reproduce\r\n\r\n1. Create google nodepool TF code with node_config block and set `tags` within the block to a list of strings, i.e. `tags=[ \"one\", \"two\" ]`\r\n2. Terraform apply to create the nodepool with this node config\r\n3. Now update code to say `tags=null`\r\n4. Terraform apply and see the tags removed rather than ignored\r\n", + body: "\r\n\r\n### Community Note\r\n\r\n* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request.\r\n* Please do not leave _+1_ or _me too_ comments, they generate extra noise for issue followers and do not help prioritize the request.\r\n* If you are interested in working on this issue or have submitted a pull request, please leave a comment.\r\n* If an issue is assigned to the `modular-magician` user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to `hashibot`, a community member has claimed the issue already.\r\n\r\n\r\n\r\n### Terraform Version\r\n\r\n\r\nTerraform v1.3.7\r\non linux_amd64\r\nprovider registry.terraform.io/hashicorp/google v4.48.0\r\n\r\n### Affected Resource(s)\r\n\r\n\r\n\r\n* google_container_node_pool\r\n* google_container_cluster\r\n\r\n### Terraform Configuration Files\r\n\r\n\r\n\r\n```tf\r\nnode_config {\r\n tags = null\r\n}\r\n```\r\n### Expected Behavior\r\n\r\nIn above code, if there already exists a list of tags defined in the `node_config` block then I would expect TF to ignore this tags field and leave them as they are\r\n\r\n### Actual Behavior\r\n\r\nTF sets the tags to an empty list, [], thus removing existing tags\r\n\r\n### Steps to Reproduce\r\n\r\n1. Create google nodepool TF code with node_config block and set `tags` within the block to a list of strings, i.e. `tags=[ \"one\", \"two\" ]`\r\n2. Terraform apply to create the nodepool with this node config\r\n3. Now update code to say `tags=null`\r\n4. Terraform apply and see the tags removed rather than ignored\r\n", expectedResources: []string{"google_container_node_pool", "google_container_cluster"}, }, "2023 enhancement": { diff --git a/tools/issue-labeler/main.go b/tools/issue-labeler/main.go index d83ff58b8250..d22535daccfd 100644 --- a/tools/issue-labeler/main.go +++ b/tools/issue-labeler/main.go @@ -1,41 +1,7 @@ package main -import ( - "flag" - "fmt" - "os" - "sort" - "strings" - - "github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler/labeler" - "github.com/golang/glog" -) - -var flagBackfillDate = flag.String("backfill-date", "", "run in backfill mode to apply labels to issues filed after given date") -var flagDryRun = flag.Bool("backfill-dry-run", false, "when combined with backfill-date, perform a dry run of backfill mode") +import "github.com/GoogleCloudPlatform/magic-modules/tools/issue-labeler/cmd" func main() { - flag.Parse() - - regexpLabels, err := labeler.BuildRegexLabels(labeler.EnrolledTeamsYaml) - if err != nil { - glog.Exitf("Error building regex labels: %v", err) - } - - if *flagBackfillDate == "" { - issueBody := os.Getenv("ISSUE_BODY") - affectedResources := labeler.ExtractAffectedResources(issueBody) - labels := labeler.ComputeLabels(affectedResources, regexpLabels) - - if len(labels) > 0 { - labels = append(labels, "forward/review") - sort.Strings(labels) - fmt.Println(`["` + strings.Join(labels, `", "`) + `"]`) - } - } else { - repository := "hashicorp/terraform-provider-google" - issues := labeler.GetIssues(repository, *flagBackfillDate) - issueUpdates := labeler.ComputeIssueUpdates(issues, regexpLabels) - labeler.UpdateIssues(repository, issueUpdates, *flagDryRun) - } + cmd.Execute() } diff --git a/tools/teamcity-diff-check/go.mod b/tools/teamcity-diff-check/go.mod new file mode 100644 index 000000000000..c0643ef9ac8c --- /dev/null +++ b/tools/teamcity-diff-check/go.mod @@ -0,0 +1,3 @@ +module github.com/GoogleCloudPlatform/magic-modules/tools/teamcity-diff-check + +go 1.23.2 diff --git a/tools/teamcity-diff-check/main.go b/tools/teamcity-diff-check/main.go index 301306f5b319..eba516ae27c9 100644 --- a/tools/teamcity-diff-check/main.go +++ b/tools/teamcity-diff-check/main.go @@ -9,31 +9,58 @@ import ( "regexp" ) -var serviceFile = flag.String("service_file", "services_ga", "kotlin service file to be parsed") +var version = flag.String("version", "", "the provider version under test. Must be `ga` or `beta`") +var teamcityServiceFile = flag.String("teamcity_services", "", "path to a kotlin service file to be parsed") +var providerServiceFile = flag.String("provider_services", "", "path to a .txt file listing all service packages in the provider") -func serviceDifference(gS, tS []string) []string { - t := make(map[string]struct{}, len(tS)) - for _, s := range tS { - t[s] = struct{}{} - } +// listDifference checks that all the items in list B are present in list A +func listDifference(listA, listB []string) error { + a := make(map[string]struct{}, len(listA)) + for _, s := range listA { + a[s] = struct{}{} + } var diff []string - for _, s := range gS { - if _, found := t[s]; !found { + for _, s := range listB { + if _, found := a[s]; !found { diff = append(diff, s) } } - return diff + if len(diff) > 0 { + return fmt.Errorf("%v", diff) + } + + return nil } func main() { flag.Parse() - file, err := os.Open(*serviceFile + ".txt") + ga := *version == "ga" + beta := *version == "beta" + if !ga && !beta { + fmt.Fprint(os.Stderr, "the flag `version` must be set to either `ga` or `beta`, and is case sensitive\n") + os.Exit(1) + } + + err := compareServices(*teamcityServiceFile, *providerServiceFile) + if err != nil { + fmt.Fprintf(os.Stderr, "Errors when inspecting the %s version of the Google provider\n", *version) + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + os.Exit(1) + } + + fmt.Fprintf(os.Stdout, "All services present in the %s provider codebase are present in TeamCity config, and vice versa\n", *version) +} + +// compareServices contains most of the logic of the main function, but is separated to make the code more testable +func compareServices(teamcityServiceFile, providerServiceFile string) error { + + // Get array of services from the provider service list file + file, err := os.Open(providerServiceFile) if err != nil { - fmt.Println(err) - return + return fmt.Errorf("error opening provider service list file: %w", err) } defer file.Close() @@ -42,31 +69,28 @@ func main() { for scanner.Scan() { googleServices = append(googleServices, scanner.Text()) } + if len(googleServices) == 0 { + return fmt.Errorf("could not find any services in the provider service list file %s", providerServiceFile) + } - //////////////////////////////////////////////////////////////////////////////// - - filePath := fmt.Sprintf("mmv1/third_party/terraform/.teamcity/components/inputs/%s.kt", *serviceFile) - f, err := os.Open(fmt.Sprintf("../../%s", filePath)) // Need to make path relative to where the script is called + // Get array of services from the TeamCity service list file + f, err := os.Open(teamcityServiceFile) if err != nil { - panic(err) + return fmt.Errorf("error opening TeamCity service list file: %w", err) } - // Get the file size stat, err := f.Stat() if err != nil { - fmt.Println(err) - return + return fmt.Errorf("error stating TeamCity service list file: %w", err) } - // Read the file into a byte slice bs := make([]byte, stat.Size()) _, err = bufio.NewReader(f).Read(bs) if err != nil && err != io.EOF { - fmt.Println(err) - return + return fmt.Errorf("error processing TeamCity service list file: %w", err) } - // Regex pattern captures "services" from *serviceFile. + // Regex pattern captures "services" from the Kotlin service list file. pattern := regexp.MustCompile(`(?m)"(?P\w+)"\sto\s+mapOf`) template := []byte("$service") @@ -74,20 +98,33 @@ func main() { dst := []byte{} teamcityServices := []string{} - // For each match of the regex in the content. for _, submatches := range pattern.FindAllSubmatchIndex(bs, -1) { service := pattern.Expand(dst, template, bs, submatches) teamcityServices = append(teamcityServices, string(service)) } if len(teamcityServices) == 0 { - fmt.Fprintf(os.Stderr, "error: script could not find any services listed in the file %s.kt .\n", filePath) - os.Exit(1) + return fmt.Errorf("could not find any services in the TeamCity service list file %s", teamcityServiceFile) } - if diff := serviceDifference(googleServices, teamcityServices); len(diff) != 0 { - fmt.Fprintf(os.Stderr, "error: missing services detected in %s\n", filePath) - fmt.Fprintf(os.Stderr, "Please update file to include these new services: %s\n", diff) - os.Exit(1) + // Determine diffs + errTeamCity := listDifference(teamcityServices, googleServices) + errProvider := listDifference(googleServices, teamcityServices) + + switch { + case errTeamCity != nil && errProvider != nil: + return fmt.Errorf(`mismatches detected: +TeamCity service file is missing services present in the provider: %s +Provider codebase is missing services present in the TeamCity service file: %s`, + errTeamCity, errProvider) + case errTeamCity != nil: + return fmt.Errorf(`mismatches detected: +TeamCity service file is missing services present in the provider: %s`, + errTeamCity) + case errProvider != nil: + return fmt.Errorf(`mismatches detected: +Provider codebase is missing services present in the TeamCity service file: %s`, + errProvider) } + return nil } diff --git a/tools/teamcity-diff-check/main_test.go b/tools/teamcity-diff-check/main_test.go new file mode 100644 index 000000000000..2166bf9acebb --- /dev/null +++ b/tools/teamcity-diff-check/main_test.go @@ -0,0 +1,159 @@ +package main + +import ( + "regexp" + "testing" +) + +func Test_main_happyPaths(t *testing.T) { + testCases := map[string]struct { + providerServiceFile string + teamcityServiceFile string + expectError bool + errorRegex *regexp.Regexp + missingServiceRegex *regexp.Regexp + }{ + "everything matches": { + providerServiceFile: "./test-fixtures/everything-ok/ga-services.txt", + teamcityServiceFile: "./test-fixtures/everything-ok/services_ga.kt", + }, + "something missing in TeamCity config present in provider code": { + providerServiceFile: "./test-fixtures/mismatch-teamcity/ga-services.txt", + teamcityServiceFile: "./test-fixtures/mismatch-teamcity/services_ga.kt", + expectError: true, + errorRegex: regexp.MustCompile("TeamCity service file is missing services present in the provider"), + missingServiceRegex: regexp.MustCompile("[pubsub]"), + }, + "something missing in provider code present in TeamCity config": { + providerServiceFile: "./test-fixtures/mismatch-provider/ga-services.txt", + teamcityServiceFile: "./test-fixtures/mismatch-provider/services_ga.kt", + expectError: true, + errorRegex: regexp.MustCompile("Provider codebase is missing services present in the TeamCity service file"), + missingServiceRegex: regexp.MustCompile("[compute]"), + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + err := compareServices(tc.teamcityServiceFile, tc.providerServiceFile) + if err != nil && !tc.expectError { + t.Fatalf("saw an unexpected error: %s", err) + } + if err == nil && tc.expectError { + t.Fatalf("expected an error but saw none") + } + + if err == nil { + // Stop handling of non-error test cases + return + } + + if !tc.errorRegex.MatchString(err.Error()) { + t.Fatalf("expected error to contain a match for regex `%s`, got error string: `%s`", tc.errorRegex.String(), err) + } + if !tc.missingServiceRegex.MatchString(err.Error()) { + t.Fatalf("expected error to contain a match for regex `%s`, got error string: `%s`", tc.errorRegex.String(), err) + } + }) + } +} + +func Test_main_unhappyPaths(t *testing.T) { + testCases := map[string]struct { + providerServiceFile string + teamcityServiceFile string + expectError bool + errorRegex *regexp.Regexp + }{ + "cannot find provider service file": { + providerServiceFile: "./test-fixtures/doesnt-exist.txt", + teamcityServiceFile: "./test-fixtures/everything-ok/services_ga.kt", + expectError: true, + errorRegex: regexp.MustCompile("error opening provider service list file: open ./test-fixtures/doesnt-exist.txt"), + }, + "cannot find TeamCity service file": { + providerServiceFile: "./test-fixtures/everything-ok/ga-services.txt", + teamcityServiceFile: "./test-fixtures/everything-ok/doesnt-exist.kt", + expectError: true, + errorRegex: regexp.MustCompile("error opening TeamCity service list file: open ./test-fixtures/everything-ok/doesnt-exist.kt"), + }, + "empty TeamCity service file": { + providerServiceFile: "./test-fixtures/everything-ok/ga-services.txt", + teamcityServiceFile: "./test-fixtures/empty-files/services_ga.kt", + expectError: true, + errorRegex: regexp.MustCompile("could not find any services in the TeamCity service list file ./test-fixtures/empty-files/services_ga.kt"), + }, + "empty provider service file": { + providerServiceFile: "./test-fixtures/empty-files/ga-services.txt", + teamcityServiceFile: "./test-fixtures/everything-ok/services_ga.kt", + expectError: true, + errorRegex: regexp.MustCompile("could not find any services in the provider service list file ./test-fixtures/empty-files/ga-services.txt"), + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + err := compareServices(tc.teamcityServiceFile, tc.providerServiceFile) + if err != nil && !tc.expectError { + t.Fatalf("saw an unexpected error: %s", err) + } + if err == nil && tc.expectError { + t.Fatalf("expected an error but saw none") + } + + if !tc.errorRegex.MatchString(err.Error()) { + t.Fatalf("expected error to contain a match for regex `%s`, got error string: `%s`", tc.errorRegex.String(), err) + } + }) + } +} + +func Test_listDifference(t *testing.T) { + testCases := map[string]struct { + a []string + b []string + expectDiff bool + errorRegex *regexp.Regexp + }{ + "detects when lists match": { + a: []string{"a", "c", "b"}, + b: []string{"a", "b", "c"}, + }, + "detects when items from list A is missing items present in list B - 1 missing": { + a: []string{"a", "b"}, + b: []string{"a", "c", "b"}, + expectDiff: true, + errorRegex: regexp.MustCompile("[c]"), + }, + "detects when items from list A is missing items present in list B - 2 missing": { + a: []string{"b"}, + b: []string{"a", "c", "b"}, + expectDiff: true, + errorRegex: regexp.MustCompile("[a, c]"), + }, + "doesn't detect differences if list A is a superset of list B": { + a: []string{"a", "b", "c"}, + b: []string{"a", "c"}, + expectDiff: false, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + err := listDifference(tc.a, tc.b) + if !tc.expectDiff && (err != nil) { + t.Fatalf("saw an unexpected diff error: %s", err) + } + if tc.expectDiff && (err == nil) { + t.Fatalf("expected a diff error but saw none") + } + if !tc.expectDiff && err == nil { + // Stop assertions in no error cases + return + } + if !tc.errorRegex.MatchString(err.Error()) { + t.Fatalf("expected diff error to contain a match for regex %s, error string: %s", tc.errorRegex.String(), err) + } + }) + } +} diff --git a/tools/teamcity-diff-check/test-fixtures/empty-files/ga-services.txt b/tools/teamcity-diff-check/test-fixtures/empty-files/ga-services.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/teamcity-diff-check/test-fixtures/empty-files/services_ga.kt b/tools/teamcity-diff-check/test-fixtures/empty-files/services_ga.kt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/teamcity-diff-check/test-fixtures/everything-ok/ga-services.txt b/tools/teamcity-diff-check/test-fixtures/everything-ok/ga-services.txt new file mode 100644 index 000000000000..62aec83f16e1 --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/everything-ok/ga-services.txt @@ -0,0 +1,2 @@ +compute +pubsub \ No newline at end of file diff --git a/tools/teamcity-diff-check/test-fixtures/everything-ok/services_ga.kt b/tools/teamcity-diff-check/test-fixtures/everything-ok/services_ga.kt new file mode 100644 index 000000000000..b56973ecf0ea --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/everything-ok/services_ga.kt @@ -0,0 +1,12 @@ +var ServicesListGa = mapOf( + "compute" to mapOf( + "name" to "compute", + "displayName" to "Compute", + "path" to "./google/services/compute" + ), + "pubsub" to mapOf( + "name" to "pubsub", + "displayName" to "PubSub", + "path" to "./google/services/pubsub" + ), +) \ No newline at end of file diff --git a/tools/teamcity-diff-check/test-fixtures/mismatch-provider/ga-services.txt b/tools/teamcity-diff-check/test-fixtures/mismatch-provider/ga-services.txt new file mode 100644 index 000000000000..a48da76e0d8c --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/mismatch-provider/ga-services.txt @@ -0,0 +1 @@ +pubsub \ No newline at end of file diff --git a/tools/teamcity-diff-check/test-fixtures/mismatch-provider/services_ga.kt b/tools/teamcity-diff-check/test-fixtures/mismatch-provider/services_ga.kt new file mode 100644 index 000000000000..b56973ecf0ea --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/mismatch-provider/services_ga.kt @@ -0,0 +1,12 @@ +var ServicesListGa = mapOf( + "compute" to mapOf( + "name" to "compute", + "displayName" to "Compute", + "path" to "./google/services/compute" + ), + "pubsub" to mapOf( + "name" to "pubsub", + "displayName" to "PubSub", + "path" to "./google/services/pubsub" + ), +) \ No newline at end of file diff --git a/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/ga-services.txt b/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/ga-services.txt new file mode 100644 index 000000000000..62aec83f16e1 --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/ga-services.txt @@ -0,0 +1,2 @@ +compute +pubsub \ No newline at end of file diff --git a/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/services_ga.kt b/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/services_ga.kt new file mode 100644 index 000000000000..8023d6236096 --- /dev/null +++ b/tools/teamcity-diff-check/test-fixtures/mismatch-teamcity/services_ga.kt @@ -0,0 +1,7 @@ +var ServicesListGa = mapOf( + "compute" to mapOf( + "name" to "compute", + "displayName" to "Compute", + "path" to "./google/services/compute" + ), +) \ No newline at end of file diff --git a/tpgtools/api/clouddeploy/samples/updatecanary.delivery_pipeline.json b/tpgtools/api/clouddeploy/samples/updatecanary.delivery_pipeline.json index 31451d07f9b7..cdfb5862ff5c 100644 --- a/tpgtools/api/clouddeploy/samples/updatecanary.delivery_pipeline.json +++ b/tpgtools/api/clouddeploy/samples/updatecanary.delivery_pipeline.json @@ -56,7 +56,11 @@ "httpRoute": "example-http-route", "service": "example-service", "deployment": "example-deployment", - "podSelectorLabel": "example.com/app-name" + "podSelectorLabel": "example.com/app-name", + "routeDestinations": { + "destinationIds": ["example-destination-id"], + "propagateService": true + } } } }, diff --git a/tpgtools/documentation.go b/tpgtools/documentation.go index 25c225817d00..aaa8c12eb43c 100644 --- a/tpgtools/documentation.go +++ b/tpgtools/documentation.go @@ -69,7 +69,7 @@ func mergeProperties(ga, beta []Property) []Property { betaProps[p.title] = p } inOrder := make([]string, 0) - for k, _ := range betaProps { + for k := range betaProps { inOrder = append(inOrder, k) } sort.Strings(inOrder) diff --git a/tpgtools/go.mod b/tpgtools/go.mod index ccd9d8734067..9893922153c6 100644 --- a/tpgtools/go.mod +++ b/tpgtools/go.mod @@ -4,7 +4,7 @@ go 1.23 require ( bitbucket.org/creachadair/stringset v0.0.11 - github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0 + github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0 github.com/golang/glog v1.1.2 github.com/hashicorp/hcl v1.0.0 github.com/kylelemons/godebug v1.1.0 diff --git a/tpgtools/go.sum b/tpgtools/go.sum index d3144c1199b7..ef2bc02873bf 100644 --- a/tpgtools/go.sum +++ b/tpgtools/go.sum @@ -6,8 +6,8 @@ cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0 h1:7tFkHNjfjm7dYnjqyuzMon+31lPaMTjca3OuamWd0Oo= -github.com/GoogleCloudPlatform/declarative-resource-client-library v1.75.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0 h1:VH/j8GmTsvPds/NkGfo4OYr9C7R8ysikaqq4rcDUT0s= +github.com/GoogleCloudPlatform/declarative-resource-client-library v1.76.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= diff --git a/tpgtools/overrides/clouddeploy/beta/target.yaml b/tpgtools/overrides/clouddeploy/beta/target.yaml index af851d79a0c9..87b99fc0dce7 100644 --- a/tpgtools/overrides/clouddeploy/beta/target.yaml +++ b/tpgtools/overrides/clouddeploy/beta/target.yaml @@ -2,3 +2,7 @@ details: functions: - tpgresource.DefaultProviderProject +- type: COMPLEX_MAP_KEY_NAME + field: associated_entities + details: + keyname: entity_id diff --git a/tpgtools/overrides/clouddeploy/target.yaml b/tpgtools/overrides/clouddeploy/target.yaml index af851d79a0c9..ca7a0b536fff 100644 --- a/tpgtools/overrides/clouddeploy/target.yaml +++ b/tpgtools/overrides/clouddeploy/target.yaml @@ -2,3 +2,7 @@ details: functions: - tpgresource.DefaultProviderProject +- type: COMPLEX_MAP_KEY_NAME + field: associated_entities + details: + keyname: entity_id \ No newline at end of file diff --git a/tpgtools/property.go b/tpgtools/property.go index 813b89e719ae..50cb4ae3acb9 100644 --- a/tpgtools/property.go +++ b/tpgtools/property.go @@ -246,7 +246,7 @@ func (p Property) ChangeStateGetter() string { } // Builds a Getter for constructing a shallow -// version of the object for destory purposes +// version of the object for destroy purposes func (p Property) StateGetterForDestroyTest() string { pullValueFromState := fmt.Sprintf(`rs.Primary.Attributes["%s"]`, p.Name()) diff --git a/tpgtools/resource.go b/tpgtools/resource.go index c7916dd303a1..ff1eb3d56ec1 100644 --- a/tpgtools/resource.go +++ b/tpgtools/resource.go @@ -160,7 +160,7 @@ type Resource struct { // CustomSerializer defines the function this resource should use to serialize itself. CustomSerializer *string - // TerraformProductName is the Product name overriden from the DCL + // TerraformProductName is the Product name overridden from the DCL TerraformProductName *SnakeCaseProductName // The array of Samples associated with the resource diff --git a/tpgtools/sample.go b/tpgtools/sample.go index c934575ea8bd..337776018744 100644 --- a/tpgtools/sample.go +++ b/tpgtools/sample.go @@ -161,7 +161,7 @@ func findDCLReferencePackage(product SnakeCaseProductName) (DCLPackageName, erro // Otherwise, just return an error. var productOverrideKeys []Filepath - for k, _ := range productOverrides { + for k := range productOverrides { productOverrideKeys = append(productOverrideKeys, k) } return DCLPackageName(""), fmt.Errorf("can't find %q in the overrides map, which contains %v", product, productOverrideKeys) diff --git a/tpgtools/templates/resource.go.tmpl b/tpgtools/templates/resource.go.tmpl index b65085ba771f..4b58719bac91 100644 --- a/tpgtools/templates/resource.go.tmpl +++ b/tpgtools/templates/resource.go.tmpl @@ -792,7 +792,7 @@ func flatten{{$.PathType}}Labels(v map[string]string, d *schema.ResourceData) in transformed := make(map[string]interface{}) if l, ok := d.Get("labels").(map[string]interface{}); ok { - for k, _ := range l { + for k := range l { transformed[k] = v[k] } } @@ -807,7 +807,7 @@ func flatten{{$.PathType}}TerraformLabels(v map[string]string, d *schema.Resourc transformed := make(map[string]interface{}) if l, ok := d.Get("terraform_labels").(map[string]interface{}); ok { - for k, _ := range l { + for k := range l { transformed[k] = v[k] } } @@ -824,7 +824,7 @@ func flatten{{$.PathType}}Annotations(v map[string]string, d *schema.ResourceDat transformed := make(map[string]interface{}) if l, ok := d.Get("annotations").(map[string]interface{}); ok { - for k, _ := range l { + for k := range l { transformed[k] = v[k] } }