package google import ( "fmt" "strings" "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/helper/schema" "google.golang.org/api/cloudresourcemanager/v1" resourceManagerV2Beta1 "google.golang.org/api/cloudresourcemanager/v2beta1" ) var IamFolderSchema = map[string]*schema.Schema{ "folder": { Type: schema.TypeString, Required: true, ForceNew: true, }, } type FolderIamUpdater struct { folderId string Config *Config } func NewFolderIamUpdater(d *schema.ResourceData, config *Config) (ResourceIamUpdater, error) { return &FolderIamUpdater{ folderId: canonicalFolderId(d.Get("folder").(string)), Config: config, }, nil } func FolderIdParseFunc(d *schema.ResourceData, _ *Config) error { d.Set("folder", d.Id()) return nil } func (u *FolderIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { return getFolderIamPolicyByFolderName(u.folderId, u.Config) } func (u *FolderIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { v2BetaPolicy, err := v1PolicyToV2Beta(policy) if err != nil { return err } _, err = u.Config.clientResourceManagerV2Beta1.Folders.SetIamPolicy(u.folderId, &resourceManagerV2Beta1.SetIamPolicyRequest{ Policy: v2BetaPolicy, }).Do() if err != nil { return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) } return nil } func (u *FolderIamUpdater) GetResourceId() string { return u.folderId } func (u *FolderIamUpdater) GetMutexKey() string { return fmt.Sprintf("iam-folder-%s", u.folderId) } func (u *FolderIamUpdater) DescribeResource() string { return fmt.Sprintf("folder %q", u.folderId) } func canonicalFolderId(folder string) string { if strings.HasPrefix(folder, "folders/") { return folder } return "folders/" + folder } // v1 and v2beta policy are identical func v1PolicyToV2Beta(in *cloudresourcemanager.Policy) (*resourceManagerV2Beta1.Policy, error) { out := &resourceManagerV2Beta1.Policy{} err := Convert(in, out) if err != nil { return nil, errwrap.Wrapf("Cannot convert a v1 policy to a v2beta policy: {{err}}", err) } return out, nil } func v2BetaPolicyToV1(in *resourceManagerV2Beta1.Policy) (*cloudresourcemanager.Policy, error) { out := &cloudresourcemanager.Policy{} err := Convert(in, out) if err != nil { return nil, errwrap.Wrapf("Cannot convert a v2beta policy to a v1 policy: {{err}}", err) } return out, nil } // Retrieve the existing IAM Policy for a folder func getFolderIamPolicyByFolderName(folderName string, config *Config) (*cloudresourcemanager.Policy, error) { p, err := config.clientResourceManagerV2Beta1.Folders.GetIamPolicy(folderName, &resourceManagerV2Beta1.GetIamPolicyRequest{}).Do() if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for folder %q: {{err}}", folderName), err) } v1Policy, err := v2BetaPolicyToV1(p) if err != nil { return nil, err } return v1Policy, nil } func getFolderIamPolicyByParentAndDisplayName(parent, displayName string, config *Config) (*cloudresourcemanager.Policy, error) { queryString := fmt.Sprintf("lifecycleState=ACTIVE AND parent=%s AND displayName=%s", parent, displayName) searchRequest := &resourceManagerV2Beta1.SearchFoldersRequest{ Query: queryString, } searchResponse, err := config.clientResourceManagerV2Beta1.Folders.Search(searchRequest).Do() if err != nil { if isGoogleApiErrorWithCode(err, 404) { return nil, fmt.Errorf("Folder not found: %s,%s", parent, displayName) } return nil, errwrap.Wrapf("Error reading folders: {{err}}", err) } folders := searchResponse.Folders if len(folders) != 1 { return nil, fmt.Errorf("More than one folder found") } return getFolderIamPolicyByFolderName(folders[0].Name, config) }