mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-09-28 22:16:04 +00:00
providers/google: Add acceptance tests for Project IAM
This commit is contained in:
parent
f57670652d
commit
39109607a2
@ -9,10 +9,21 @@ import (
|
|||||||
"google.golang.org/api/cloudresourcemanager/v1"
|
"google.golang.org/api/cloudresourcemanager/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// dataSourceGoogleIamPolicy returns a *schema.Resource that allows a customer
|
||||||
|
// to express a Google Cloud IAM policy in a data resource. This is an example
|
||||||
|
// of how the schema would be used in a config:
|
||||||
|
//
|
||||||
|
// data "google_iam_policy" "admin" {
|
||||||
|
// binding {
|
||||||
|
// role = "roles/storage.objectViewer"
|
||||||
|
// members = [
|
||||||
|
// "user:evanbrown@google.com",
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
func dataSourceGoogleIamPolicy() *schema.Resource {
|
func dataSourceGoogleIamPolicy() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Read: dataSourceGoogleIamPolicyRead,
|
Read: dataSourceGoogleIamPolicyRead,
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"binding": {
|
"binding": {
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeSet,
|
||||||
@ -40,6 +51,45 @@ func dataSourceGoogleIamPolicy() *schema.Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dataSourceGoogleIamPolicyRead reads a data source from config and writes it
|
||||||
|
// to state.
|
||||||
|
func dataSourceGoogleIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
var policy cloudresourcemanager.Policy
|
||||||
|
var bindings []*cloudresourcemanager.Binding
|
||||||
|
|
||||||
|
// The schema supports multiple binding{} blocks
|
||||||
|
bset := d.Get("binding").(*schema.Set)
|
||||||
|
|
||||||
|
// All binding{} blocks will be converted and stored in an array
|
||||||
|
bindings = make([]*cloudresourcemanager.Binding, bset.Len())
|
||||||
|
policy.Bindings = bindings
|
||||||
|
|
||||||
|
// Convert each config binding into a cloudresourcemanager.Binding
|
||||||
|
for i, v := range bset.List() {
|
||||||
|
binding := v.(map[string]interface{})
|
||||||
|
policy.Bindings[i] = &cloudresourcemanager.Binding{
|
||||||
|
Role: binding["role"].(string),
|
||||||
|
Members: dataSourceGoogleIamPolicyMembers(binding["members"].(*schema.Set)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal cloudresourcemanager.Policy to JSON suitable for storing in state
|
||||||
|
pjson, err := json.Marshal(&policy)
|
||||||
|
if err != nil {
|
||||||
|
// should never happen if the above code is correct
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pstring := string(pjson)
|
||||||
|
|
||||||
|
d.Set("policy", pstring)
|
||||||
|
d.SetId(strconv.Itoa(hashcode.String(pstring)))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataSourceGoogleIamPolicyMembers converts a set of members in a binding
|
||||||
|
// (a member is a principal, usually an e-mail address) into an array of
|
||||||
|
// string.
|
||||||
func dataSourceGoogleIamPolicyMembers(d *schema.Set) []string {
|
func dataSourceGoogleIamPolicyMembers(d *schema.Set) []string {
|
||||||
var members []string
|
var members []string
|
||||||
members = make([]string, d.Len())
|
members = make([]string, d.Len())
|
||||||
@ -49,33 +99,3 @@ func dataSourceGoogleIamPolicyMembers(d *schema.Set) []string {
|
|||||||
}
|
}
|
||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceGoogleIamPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
doc := &cloudresourcemanager.Policy{}
|
|
||||||
|
|
||||||
var bindings []*cloudresourcemanager.Binding
|
|
||||||
|
|
||||||
bindingStatements := d.Get("binding").(*schema.Set)
|
|
||||||
bindings = make([]*cloudresourcemanager.Binding, bindingStatements.Len())
|
|
||||||
doc.Bindings = bindings
|
|
||||||
|
|
||||||
for i, bindingRaw := range bindingStatements.List() {
|
|
||||||
bindingStatement := bindingRaw.(map[string]interface{})
|
|
||||||
doc.Bindings[i] = &cloudresourcemanager.Binding{
|
|
||||||
Role: bindingStatement["role"].(string),
|
|
||||||
Members: dataSourceGoogleIamPolicyMembers(bindingStatement["members"].(*schema.Set)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonDoc, err := json.MarshalIndent(doc, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
// should never happen if the above code is correct
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
jsonString := string(jsonDoc)
|
|
||||||
|
|
||||||
d.Set("policy", jsonString)
|
|
||||||
d.SetId(strconv.Itoa(hashcode.String(jsonString)))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -12,6 +12,17 @@ import (
|
|||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// resourceGoogleProject returns a *schema.Resource that allows a customer
|
||||||
|
// to declare a Google Cloud Project resource. //
|
||||||
|
// Only the 'policy' property of a project may be updated. All other properties
|
||||||
|
// are computed.
|
||||||
|
//
|
||||||
|
// This example shows a project with a policy declared in config:
|
||||||
|
//
|
||||||
|
// resource "google_project" "my-project" {
|
||||||
|
// project = "a-project-id"
|
||||||
|
// policy = "${data.google_iam_policy.admin.policy}"
|
||||||
|
// }
|
||||||
func resourceGoogleProject() *schema.Resource {
|
func resourceGoogleProject() *schema.Resource {
|
||||||
return &schema.Resource{
|
return &schema.Resource{
|
||||||
Create: resourceGoogleProjectCreate,
|
Create: resourceGoogleProjectCreate,
|
||||||
@ -49,6 +60,9 @@ func resourceGoogleProject() *schema.Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This resource supports creation, but not in the traditional sense.
|
||||||
|
// A new Google Cloud Project can not be created. Instead, an existing Project
|
||||||
|
// is initialized and made available as a Terraform resource.
|
||||||
func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error {
|
func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
@ -142,8 +156,8 @@ func resourceGoogleProjectUpdate(d *schema.ResourceData, meta interface{}) error
|
|||||||
newPString = "{}"
|
newPString = "{}"
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPStringf, _ := json.MarshalIndent(oldPString, " ", " ")
|
oldPStringf, _ := json.MarshalIndent(oldPString, "", " ")
|
||||||
newPStringf, _ := json.MarshalIndent(newPString, " ", " ")
|
newPStringf, _ := json.MarshalIndent(newPString, "", " ")
|
||||||
log.Printf("[DEBUG]: Old policy: %v\nNew policy: %v", string(oldPStringf), string(newPStringf))
|
log.Printf("[DEBUG]: Old policy: %v\nNew policy: %v", string(oldPStringf), string(newPStringf))
|
||||||
|
|
||||||
var oldPolicy, newPolicy cloudresourcemanager.Policy
|
var oldPolicy, newPolicy cloudresourcemanager.Policy
|
||||||
@ -158,24 +172,28 @@ func resourceGoogleProjectUpdate(d *schema.ResourceData, meta interface{}) error
|
|||||||
// in the old but absent in the new
|
// in the old but absent in the new
|
||||||
oldMap := rolesToMembersMap(oldPolicy.Bindings)
|
oldMap := rolesToMembersMap(oldPolicy.Bindings)
|
||||||
newMap := rolesToMembersMap(newPolicy.Bindings)
|
newMap := rolesToMembersMap(newPolicy.Bindings)
|
||||||
deleted := make(map[string]string)
|
deleted := make(map[string]map[string]bool)
|
||||||
|
|
||||||
// Get each role and its associated members in the old state
|
// Get each role and its associated members in the old state
|
||||||
for role, members := range oldMap {
|
for role, members := range oldMap {
|
||||||
|
// Initialize map for role
|
||||||
|
if _, ok := deleted[role]; !ok {
|
||||||
|
deleted[role] = make(map[string]bool)
|
||||||
|
}
|
||||||
// The role exists in the new state
|
// The role exists in the new state
|
||||||
if _, ok := newMap[role]; ok {
|
if _, ok := newMap[role]; ok {
|
||||||
// Check each memeber
|
// Check each memeber
|
||||||
for member, _ := range members {
|
for member, _ := range members {
|
||||||
// Member does not exist in new state, so it was deleted
|
// Member does not exist in new state, so it was deleted
|
||||||
if _, ok = newMap[role][member]; !ok {
|
if _, ok = newMap[role][member]; !ok {
|
||||||
deleted[role] = member
|
deleted[role][member] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This indicates an entire role was deleted. Mark all members
|
// This indicates an entire role was deleted. Mark all members
|
||||||
// for delete.
|
// for delete.
|
||||||
for member, _ := range members {
|
for member, _ := range members {
|
||||||
deleted[role] = member
|
deleted[role][member] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,8 +215,10 @@ func resourceGoogleProjectUpdate(d *schema.ResourceData, meta interface{}) error
|
|||||||
|
|
||||||
// Remove any roles and members that were explicitly deleted
|
// Remove any roles and members that were explicitly deleted
|
||||||
mergedBindingsMap := rolesToMembersMap(mergedBindings)
|
mergedBindingsMap := rolesToMembersMap(mergedBindings)
|
||||||
for role, member := range deleted {
|
for role, members := range deleted {
|
||||||
delete(mergedBindingsMap[role], member)
|
for member, _ := range members {
|
||||||
|
delete(mergedBindingsMap[role], member)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Bindings = rolesToMembersBinding(mergedBindingsMap)
|
p.Bindings = rolesToMembersBinding(mergedBindingsMap)
|
||||||
@ -222,6 +242,7 @@ func resourceGoogleProjectDelete(d *schema.ResourceData, meta interface{}) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve the existing IAM Policy for a Project
|
||||||
func getProjectIamPolicy(project string, config *Config) (*cloudresourcemanager.Policy, error) {
|
func getProjectIamPolicy(project string, config *Config) (*cloudresourcemanager.Policy, error) {
|
||||||
p, err := config.clientResourceManager.Projects.GetIamPolicy(project,
|
p, err := config.clientResourceManager.Projects.GetIamPolicy(project,
|
||||||
&cloudresourcemanager.GetIamPolicyRequest{}).Do()
|
&cloudresourcemanager.GetIamPolicyRequest{}).Do()
|
||||||
|
@ -1,25 +1,186 @@
|
|||||||
package google
|
package google
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"google.golang.org/api/cloudresourcemanager/v1"
|
"google.golang.org/api/cloudresourcemanager/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Binding []*cloudresourcemanager.Binding
|
var (
|
||||||
|
projectId = multiEnvSearch([]string{
|
||||||
|
"GOOGLE_PROJECT",
|
||||||
|
"GCLOUD_PROJECT",
|
||||||
|
"CLOUDSDK_CORE_PROJECT",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
func (b Binding) Len() int {
|
func multiEnvSearch(ks []string) string {
|
||||||
return len(b)
|
for _, k := range ks {
|
||||||
|
if v := os.Getenv(k); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Binding) Swap(i, j int) {
|
// Test that a Project resource can be created and destroyed
|
||||||
b[i], b[j] = b[j], b[i]
|
func TestAccGoogleProject_associate(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccGoogleProject_basic, projectId),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckGoogleProjectExists("google_project.acceptance"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Binding) Less(i, j int) bool {
|
// Test that a Project resource can be created, an IAM Policy
|
||||||
return b[i].Role < b[j].Role
|
// associated with it, and then destroyed
|
||||||
|
func TestAccGoogleProject_iamPolicy1(t *testing.T) {
|
||||||
|
var policy *cloudresourcemanager.Policy
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckGoogleProjectDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
// First step inventories the project's existing IAM policy
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccGoogleProject_basic, projectId),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccGoogleProjectExistingPolicy(policy),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// Second step applies an IAM policy from a data source. The application
|
||||||
|
// merges policies, so we validate the expected state.
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccGoogleProject_policy1, projectId),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckGoogleProjectExists("google_project.acceptance"),
|
||||||
|
testAccCheckGoogleProjectIamPolicyIsMerged("google_project.acceptance", "data.google_iam_policy.admin", policy),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// Finally, remove the custom IAM policy from config and apply, then
|
||||||
|
// confirm that the project is in its original state.
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccGoogleProject_basic, projectId),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckGoogleProjectDestroy(s *terraform.State) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the existing policy (if any) for a GCP Project
|
||||||
|
func testAccGoogleProjectExistingPolicy(p *cloudresourcemanager.Policy) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
c := testAccProvider.Meta().(*Config)
|
||||||
|
var err error
|
||||||
|
p, err = getProjectIamPolicy(projectId, c)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to retrieve IAM Policy for project %q: %s", projectId, err)
|
||||||
|
}
|
||||||
|
if len(p.Bindings) == 0 {
|
||||||
|
return fmt.Errorf("Refuse to run test against project with zero IAM Bindings. This is likely an error in the test code that is not properly identifying the IAM policy of a project.")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckGoogleProjectExists(r string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[r]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID != projectId {
|
||||||
|
return fmt.Errorf("Expected project %q to match ID %q in state", projectId, rs.Primary.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckGoogleProjectIamPolicyIsMerged(projectRes, policyRes string, original *cloudresourcemanager.Policy) 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 != projectId {
|
||||||
|
return fmt.Errorf("Expected project %q to match ID %q in state", projectId, project.Primary.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectP, policyP cloudresourcemanager.Policy
|
||||||
|
// The project should have a policy
|
||||||
|
ps, ok := project.Primary.Attributes["policy"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Project resource %q did not have a 'policy' attribute", project.Primary.ID)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(ps), &projectP); err != nil {
|
||||||
|
return 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"]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Policy resource %q did not have a 'policy' attribute", policy.Primary.ID)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(ps), &policyP); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bindings in both policies should be identical
|
||||||
|
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 nil
|
||||||
|
|
||||||
|
// Merge the project policy in Terrafomr state with the policy the project had before the config was applied
|
||||||
|
expected := make([]*cloudresourcemanager.Binding, 0)
|
||||||
|
expected = append(expected, original.Bindings...)
|
||||||
|
expected = append(expected, projectP.Bindings...)
|
||||||
|
expectedM := mergeBindings(expected)
|
||||||
|
|
||||||
|
// Retrieve the actual policy from the project
|
||||||
|
c := testAccProvider.Meta().(*Config)
|
||||||
|
actual, err := getProjectIamPolicy(projectId, c)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to retrieve IAM Policy for project %q: %s", projectId, err)
|
||||||
|
}
|
||||||
|
actualM := mergeBindings(actual.Bindings)
|
||||||
|
|
||||||
|
// The bindings should match, indicating the policy was successfully applied and merged
|
||||||
|
if !reflect.DeepEqual(derefBindings(actualM), derefBindings(expectedM)) {
|
||||||
|
return fmt.Errorf("Actual and expected project policies do not match: actual policy is %+v, expected policy is %+v", derefBindings(actualM), derefBindings(expectedM))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIamRolesToMembersBinding(t *testing.T) {
|
func TestIamRolesToMembersBinding(t *testing.T) {
|
||||||
@ -148,15 +309,6 @@ func TestIamRolesToMembersMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func derefBindings(b []*cloudresourcemanager.Binding) []cloudresourcemanager.Binding {
|
|
||||||
db := make([]cloudresourcemanager.Binding, len(b))
|
|
||||||
|
|
||||||
for i, v := range b {
|
|
||||||
db[i] = *v
|
|
||||||
}
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIamMergeBindings(t *testing.T) {
|
func TestIamMergeBindings(t *testing.T) {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
input []*cloudresourcemanager.Binding
|
input []*cloudresourcemanager.Binding
|
||||||
@ -270,3 +422,52 @@ func TestIamMergeBindings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func derefBindings(b []*cloudresourcemanager.Binding) []cloudresourcemanager.Binding {
|
||||||
|
db := make([]cloudresourcemanager.Binding, len(b))
|
||||||
|
|
||||||
|
for i, v := range b {
|
||||||
|
db[i] = *v
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
type Binding []*cloudresourcemanager.Binding
|
||||||
|
|
||||||
|
func (b Binding) Len() int {
|
||||||
|
return len(b)
|
||||||
|
}
|
||||||
|
func (b Binding) Swap(i, j int) {
|
||||||
|
b[i], b[j] = b[j], b[i]
|
||||||
|
}
|
||||||
|
func (b Binding) Less(i, j int) bool {
|
||||||
|
return b[i].Role < b[j].Role
|
||||||
|
}
|
||||||
|
|
||||||
|
var testAccGoogleProject_basic = `
|
||||||
|
resource "google_project" "acceptance" {
|
||||||
|
project = "%v"
|
||||||
|
}`
|
||||||
|
|
||||||
|
var testAccGoogleProject_policy1 = `
|
||||||
|
resource "google_project" "acceptance" {
|
||||||
|
project = "%v"
|
||||||
|
policy = "${data.google_iam_policy.admin.policy}"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "google_iam_policy" "admin" {
|
||||||
|
binding {
|
||||||
|
role = "roles/storage.objectViewer"
|
||||||
|
members = [
|
||||||
|
"user:evanbrown@google.com",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
binding {
|
||||||
|
role = "roles/compute.instanceAdmin"
|
||||||
|
members = [
|
||||||
|
"user:evanbrown@google.com",
|
||||||
|
"user:evandbrown@gmail.com",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}`
|
||||||
|
Loading…
Reference in New Issue
Block a user