diff --git a/mmv1/products/cloudidentity/terraform.yaml b/mmv1/products/cloudidentity/terraform.yaml index bf8bfce81406..d489e82b1ff2 100644 --- a/mmv1/products/cloudidentity/terraform.yaml +++ b/mmv1/products/cloudidentity/terraform.yaml @@ -42,6 +42,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides post_create: templates/terraform/post_create/set_computed_name.erb custom_import: templates/terraform/custom_import/set_id_name_with_slashes.go.erb GroupMembership: !ruby/object:Overrides::Terraform::ResourceOverride + read_error_transform: "transformCloudIdentityGroupMembershipReadError" docs: !ruby/object:Provider::Terraform::Docs warning: | If you are using User ADCs (Application Default Credentials) with this resource, diff --git a/mmv1/third_party/terraform/tests/resource_cloud_identity_group_membership_test.go.erb b/mmv1/third_party/terraform/tests/resource_cloud_identity_group_membership_test.go.erb index 7932b8bd5488..dbd9e5f8cd2b 100644 --- a/mmv1/third_party/terraform/tests/resource_cloud_identity_group_membership_test.go.erb +++ b/mmv1/third_party/terraform/tests/resource_cloud_identity_group_membership_test.go.erb @@ -5,6 +5,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "google.golang.org/api/iam/v1" ) func TestAccCloudIdentityGroupMembership_update(t *testing.T) { @@ -176,6 +177,90 @@ resource "google_cloud_identity_group_membership" "basic" { `, context) } +func TestAccCloudIdentityGroupMembership_membershipDoesNotExist(t *testing.T) { + // Skip VCR because the service account needs to be created/deleted out of + // band, and so those calls aren't recorded + skipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "org_domain": getTestOrgDomainFromEnv(t), + "cust_id": getTestCustIdFromEnv(t), + "random_suffix": randString(t, 10), + } + + saId := "tf-test-sa-" + randString(t, 10) + project := getTestProjectFromEnv() + config := BootstrapConfig(t) + + r := &iam.CreateServiceAccountRequest{ + AccountId: saId, + ServiceAccount: &iam.ServiceAccount{}, + } + + sa, err := config.NewIamClient(config.userAgent).Projects.ServiceAccounts.Create("projects/" + project, r).Do() + if err != nil { + t.Fatalf("Error creating service account: %s", err) + } + + context["member_id"] = sa.Email + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudIdentityGroupMembershipDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudIdentityGroupMembership_dne(context), + }, + { + PreConfig: func() { + config := googleProviderConfig(t) + + _, err := config.NewIamClient(config.userAgent).Projects.ServiceAccounts.Delete(sa.Name).Do() + if err != nil { + t.Errorf("cannot delete service account %s: %v", sa.Name, err) + return + } + }, + Config: testAccCloudIdentityGroupMembership_dne(context), + PlanOnly: true, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCloudIdentityGroupMembership_dne(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_identity_group" "group" { + display_name = "tf-test-my-identity-group-%{random_suffix}" + + parent = "customers/%{cust_id}" + + group_key { + id = "tf-test-my-identity-group-%{random_suffix}@%{org_domain}" + } + + labels = { + "cloudidentity.googleapis.com/groups.discussion_forum" = "" + } +} + +resource "google_cloud_identity_group_membership" "basic" { + group = google_cloud_identity_group.group.id + + preferred_member_key { + id = "%{member_id}" + } + + roles { + name = "MEMBER" + } +} +`, context) +} + <% unless version == 'ga' -%> func TestAccCloudIdentityGroupMembership_cloudIdentityGroupMembershipWithMemberKey(t *testing.T) { t.Parallel() diff --git a/mmv1/third_party/terraform/utils/cloud_identity_group_membership_utils.go b/mmv1/third_party/terraform/utils/cloud_identity_group_membership_utils.go new file mode 100644 index 000000000000..e2a1e22b81f7 --- /dev/null +++ b/mmv1/third_party/terraform/utils/cloud_identity_group_membership_utils.go @@ -0,0 +1,27 @@ +package google + +import ( + "log" + "strings" + + "github.com/hashicorp/errwrap" + "google.golang.org/api/googleapi" +) + +func transformCloudIdentityGroupMembershipReadError(err error) error { + if gErr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error); ok { + if gErr.Code == 403 && strings.Contains(gErr.Message, "(or it may not exist)") { + // This error occurs when either the group membership does not exist, or permission is denied. It is + // deliberately ambiguous so that existence information is not revealed to the caller. However, for + // the Read function, we can only assume that the membership does not exist, and proceed with attempting + // other operations. Since handleNotFoundError(...) expects an error code of 404 when a resource does not + // exist, to get the desired behavior, we modify the error code to be 404. + gErr.Code = 404 + } + + log.Printf("[DEBUG] Transformed CloudIdentityGroupMembership error") + return gErr + } + + return err +}