provider/google: ignore expanded v collapsed policies in diff
When comparing the config and state for google_project_iam_policy, always merge the bindings down to a common representation, to avoid a perpetual diff. Fixes #11763.
This commit is contained in:
parent
89dbaad2be
commit
9b1da31ca4
|
@ -373,6 +373,8 @@ func jsonPolicyDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
||||||
log.Printf("[ERROR] Could not unmarshal new policy %s: %v", new, err)
|
log.Printf("[ERROR] Could not unmarshal new policy %s: %v", new, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
oldPolicy.Bindings = mergeBindings(oldPolicy.Bindings)
|
||||||
|
newPolicy.Bindings = mergeBindings(newPolicy.Bindings)
|
||||||
if newPolicy.Etag != oldPolicy.Etag {
|
if newPolicy.Etag != oldPolicy.Etag {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,24 @@ func TestAccGoogleProjectIamPolicy_basic(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccCheckGoogleProjectIamPolicyIsMerged(projectRes, policyRes, pid string) resource.TestCheckFunc {
|
// Test that a non-collapsed IAM policy doesn't perpetually diff
|
||||||
|
func TestAccGoogleProjectIamPolicy_expanded(t *testing.T) {
|
||||||
|
pid := "terraform-" + acctest.RandString(10)
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccGoogleProjectAssociatePolicyExpanded(pid, pname, org),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckGoogleProjectIamPolicyExists("google_project_iam_policy.acceptance", "data.google_iam_policy.expanded", pid),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckGoogleProjectIamPolicyExists(projectRes, policyRes, pid string) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
// Get the project resource
|
// Get the project resource
|
||||||
project, ok := s.RootModule().Resources[projectRes]
|
project, ok := s.RootModule().Resources[projectRes]
|
||||||
|
@ -290,11 +307,56 @@ func testAccCheckGoogleProjectIamPolicyIsMerged(projectRes, policyRes, pid strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// The bindings in both policies should be identical
|
// The bindings in both policies should be identical
|
||||||
|
projectP.Bindings = mergeBindings(projectP.Bindings)
|
||||||
|
policyP.Bindings = mergeBindings(policyP.Bindings)
|
||||||
sort.Sort(sortableBindings(projectP.Bindings))
|
sort.Sort(sortableBindings(projectP.Bindings))
|
||||||
sort.Sort(sortableBindings(policyP.Bindings))
|
sort.Sort(sortableBindings(policyP.Bindings))
|
||||||
if !reflect.DeepEqual(derefBindings(projectP.Bindings), derefBindings(policyP.Bindings)) {
|
if !reflect.DeepEqual(derefBindings(projectP.Bindings), derefBindings(policyP.Bindings)) {
|
||||||
return fmt.Errorf("Project and data source policies do not match: project policy is %+v, data resource policy is %+v", derefBindings(projectP.Bindings), derefBindings(policyP.Bindings))
|
return fmt.Errorf("Project and data source policies do not match: project policy is %+v, data resource policy is %+v", derefBindings(projectP.Bindings), derefBindings(policyP.Bindings))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckGoogleProjectIamPolicyIsMerged(projectRes, policyRes, pid string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
// Get the project resource
|
||||||
|
project, ok := s.RootModule().Resources[projectRes]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", projectRes)
|
||||||
|
}
|
||||||
|
// The project ID should match the config's project ID
|
||||||
|
if project.Primary.ID != pid {
|
||||||
|
return fmt.Errorf("Expected project %q to match ID %q in state", pid, project.Primary.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := testAccCheckGoogleProjectIamPolicyExists(projectRes, policyRes, pid)(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectP, policyP cloudresourcemanager.Policy
|
||||||
|
// The project should have a policy
|
||||||
|
ps, ok := project.Primary.Attributes["policy_data"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Project resource %q did not have a 'policy_data' attribute. Attributes were %#v", project.Primary.Attributes["id"], project.Primary.Attributes)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(ps), &projectP); err != nil {
|
||||||
|
return fmt.Errorf("Could not unmarshal %s:\n: %v", ps, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data policy resource should have a policy
|
||||||
|
policy, ok := s.RootModule().Resources[policyRes]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", policyRes)
|
||||||
|
}
|
||||||
|
ps, ok = policy.Primary.Attributes["policy_data"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Data policy resource %q did not have a 'policy_data' attribute. Attributes were %#v", policy.Primary.Attributes["id"], project.Primary.Attributes)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(ps), &policyP); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Merge the project policy in Terraform state with the policy the project had before the config was applied
|
// Merge the project policy in Terraform state with the policy the project had before the config was applied
|
||||||
expected := make([]*cloudresourcemanager.Binding, 0)
|
expected := make([]*cloudresourcemanager.Binding, 0)
|
||||||
|
@ -634,3 +696,32 @@ resource "google_project" "acceptance" {
|
||||||
billing_account = "%s"
|
billing_account = "%s"
|
||||||
}`, pid, name, org, billing)
|
}`, pid, name, org, billing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccGoogleProjectAssociatePolicyExpanded(pid, name, org string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "google_project" "acceptance" {
|
||||||
|
project_id = "%s"
|
||||||
|
name = "%s"
|
||||||
|
org_id = "%s"
|
||||||
|
}
|
||||||
|
resource "google_project_iam_policy" "acceptance" {
|
||||||
|
project = "${google_project.acceptance.id}"
|
||||||
|
policy_data = "${data.google_iam_policy.expanded.policy_data}"
|
||||||
|
authoritative = false
|
||||||
|
}
|
||||||
|
data "google_iam_policy" "expanded" {
|
||||||
|
binding {
|
||||||
|
role = "roles/viewer"
|
||||||
|
members = [
|
||||||
|
"user:paddy@carvers.co",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
binding {
|
||||||
|
role = "roles/viewer"
|
||||||
|
members = [
|
||||||
|
"user:paddy@hashicorp.com",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`, pid, name, org)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue