terraform-provider-google/google/resource_google_organization_iam_test.go

207 lines
6.8 KiB
Go

package google
import (
"fmt"
"reflect"
"sort"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"google.golang.org/api/cloudresourcemanager/v1"
)
// Bindings and members are tested serially to avoid concurrent updates of the org's IAM policy.
// When concurrent changes happen, the behavior is to abort and ask the user to retry allowing
// them to see the new diff instead of blindly overriding the policy stored in GCP. This desired
// behavior however induces flakiness in our acceptance tests, hence the need for running them
// serially.
// Policies are *not tested*, because testing them will ruin changes made to the test org.
func TestAccOrganizationIam(t *testing.T) {
t.Parallel()
org := getTestOrgFromEnv(t)
account := acctest.RandomWithPrefix("tf-test")
roleId := "tfIamTest" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
// Test Iam Binding creation
Config: testAccOrganizationIamBinding_basic(account, roleId, org),
Check: testAccCheckGoogleOrganizationIamBindingExists("foo", "test-role", []string{
fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()),
}),
},
{
ResourceName: "google_organization_iam_binding.foo",
ImportStateId: fmt.Sprintf("%s organizations/%s/roles/%s", org, org, roleId),
ImportState: true,
ImportStateVerify: true,
},
{
// Test Iam Binding update
Config: testAccOrganizationIamBinding_update(account, roleId, org),
Check: testAccCheckGoogleOrganizationIamBindingExists("foo", "test-role", []string{
fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()),
fmt.Sprintf("serviceAccount:%s-2@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()),
}),
},
{
ResourceName: "google_organization_iam_binding.foo",
ImportStateId: fmt.Sprintf("%s organizations/%s/roles/%s", org, org, roleId),
ImportState: true,
ImportStateVerify: true,
},
{
// Test Iam Member creation (no update for member, no need to test)
Config: testAccOrganizationIamMember_basic(account, org),
Check: testAccCheckGoogleOrganizationIamMemberExists("foo", "roles/browser",
fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", account, getTestProjectFromEnv()),
),
},
{
ResourceName: "google_organization_iam_member.foo",
ImportStateId: fmt.Sprintf("%s roles/browser serviceAccount:%s@%s.iam.gserviceaccount.com", org, account, getTestProjectFromEnv()),
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccCheckGoogleOrganizationIamBindingExists(bindingResourceName, roleResourceName string, members []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
bindingRs, ok := s.RootModule().Resources["google_organization_iam_binding."+bindingResourceName]
if !ok {
return fmt.Errorf("Not found: %s", bindingResourceName)
}
roleRs, ok := s.RootModule().Resources["google_organization_iam_custom_role."+roleResourceName]
if !ok {
return fmt.Errorf("Not found: %s", roleResourceName)
}
config := testAccProvider.Meta().(*Config)
p, err := config.clientResourceManager.Organizations.GetIamPolicy("organizations/"+bindingRs.Primary.Attributes["org_id"], &cloudresourcemanager.GetIamPolicyRequest{}).Do()
if err != nil {
return err
}
for _, binding := range p.Bindings {
if binding.Role == roleRs.Primary.ID {
sort.Strings(members)
sort.Strings(binding.Members)
if reflect.DeepEqual(members, binding.Members) {
return nil
}
return fmt.Errorf("Binding found but expected members is %v, got %v", members, binding.Members)
}
}
return fmt.Errorf("No binding for role %q", roleRs.Primary.ID)
}
}
func testAccCheckGoogleOrganizationIamMemberExists(n, role, member string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources["google_organization_iam_member."+n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
config := testAccProvider.Meta().(*Config)
p, err := config.clientResourceManager.Organizations.GetIamPolicy("organizations/"+rs.Primary.Attributes["org_id"], &cloudresourcemanager.GetIamPolicyRequest{}).Do()
if err != nil {
return err
}
for _, binding := range p.Bindings {
if binding.Role == role {
for _, m := range binding.Members {
if m == member {
return nil
}
}
return fmt.Errorf("Missing member %q, got %v", member, binding.Members)
}
}
return fmt.Errorf("No binding for role %q", role)
}
}
// We are using a custom role since iam_binding is authoritative on the member list and
// we want to avoid removing members from an existing role to prevent unwanted side effects.
func testAccOrganizationIamBinding_basic(account, role, org string) string {
return fmt.Sprintf(`
resource "google_service_account" "test-account" {
account_id = "%s"
display_name = "Iam Testing Account"
}
resource "google_organization_iam_custom_role" "test-role" {
role_id = "%s"
org_id = "%s"
title = "Iam Testing Role"
permissions = ["genomics.datasets.get"]
}
resource "google_organization_iam_binding" "foo" {
org_id = "%s"
role = "${google_organization_iam_custom_role.test-role.id}"
members = ["serviceAccount:${google_service_account.test-account.email}"]
}
`, account, role, org, org)
}
func testAccOrganizationIamBinding_update(account, role, org string) string {
return fmt.Sprintf(`
resource "google_service_account" "test-account" {
account_id = "%s"
display_name = "Iam Testing Account"
}
resource "google_organization_iam_custom_role" "test-role" {
role_id = "%s"
org_id = "%s"
title = "Iam Testing Role"
permissions = ["genomics.datasets.get"]
}
resource "google_service_account" "test-account-2" {
account_id = "%s-2"
display_name = "Iam Testing Account"
}
resource "google_organization_iam_binding" "foo" {
org_id = "%s"
role = "${google_organization_iam_custom_role.test-role.id}"
members = [
"serviceAccount:${google_service_account.test-account.email}",
"serviceAccount:${google_service_account.test-account-2.email}"
]
}
`, account, role, org, account, org)
}
func testAccOrganizationIamMember_basic(account, org string) string {
return fmt.Sprintf(`
resource "google_service_account" "test-account" {
account_id = "%s"
display_name = "Iam Testing Account"
}
resource "google_organization_iam_member" "foo" {
org_id = "%s"
role = "roles/browser"
member = "serviceAccount:${google_service_account.test-account.email}"
}
`, account, org)
}