/
resource_google_organization_iam_custom_role.go
230 lines (204 loc) · 7.79 KB
/
resource_google_organization_iam_custom_role.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
package google
import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"google.golang.org/api/iam/v1"
)
func resourceGoogleOrganizationIamCustomRole() *schema.Resource {
return &schema.Resource{
Create: resourceGoogleOrganizationIamCustomRoleCreate,
Read: resourceGoogleOrganizationIamCustomRoleRead,
Update: resourceGoogleOrganizationIamCustomRoleUpdate,
Delete: resourceGoogleOrganizationIamCustomRoleDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"role_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The role id to use for this role.`,
},
"org_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The numeric ID of the organization in which you want to create a custom role.`,
},
"title": {
Type: schema.TypeString,
Required: true,
Description: `A human-readable title for the role.`,
},
"permissions": {
Type: schema.TypeSet,
Required: true,
MinItems: 1,
Description: `The names of the permissions this role grants when bound in an IAM policy. At least one permission must be specified.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"stage": {
Type: schema.TypeString,
Optional: true,
Default: "GA",
Description: `The current launch stage of the role. Defaults to GA.`,
ValidateFunc: validation.StringInSlice([]string{"ALPHA", "BETA", "GA", "DEPRECATED", "DISABLED", "EAP"}, false),
DiffSuppressFunc: emptyOrDefaultStringSuppress("ALPHA"),
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: `A human-readable description for the role.`,
},
"deleted": {
Type: schema.TypeBool,
Computed: true,
Description: `The current deleted state of the role.`,
},
"name": {
Type: schema.TypeString,
Computed: true,
Description: `The name of the role in the format organizations/{{org_id}}/roles/{{role_id}}. Like id, this field can be used as a reference in other resources such as IAM role bindings.`,
},
},
UseJSONNumber: true,
}
}
func resourceGoogleOrganizationIamCustomRoleCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
}
org := d.Get("org_id").(string)
roleId := fmt.Sprintf("organizations/%s/roles/%s", org, d.Get("role_id").(string))
orgId := fmt.Sprintf("organizations/%s", org)
// Look for role with given ID.
// If it exists in deleted state, update to match "created" role state
// If it exists and is enabled, return error - we should not try to recreate.
r, err := config.NewIamClient(userAgent).Organizations.Roles.Get(roleId).Do()
if err == nil {
if r.Deleted {
// This role was soft-deleted; update to match new state.
d.SetId(r.Name)
if err := resourceGoogleOrganizationIamCustomRoleUpdate(d, meta); err != nil {
// If update failed, make sure it wasn't actually added to state.
d.SetId("")
return err
}
} else {
// If a role with same name exists and is enabled, just return error
return fmt.Errorf("Custom project role %s already exists and must be imported", roleId)
}
} else if err := handleNotFoundError(err, d, fmt.Sprintf("Custom Organization Role %q", roleId)); err == nil {
// If no role was found, actually create a new role.
role, err := config.NewIamClient(userAgent).Organizations.Roles.Create(orgId, &iam.CreateRoleRequest{
RoleId: d.Get("role_id").(string),
Role: &iam.Role{
Title: d.Get("title").(string),
Description: d.Get("description").(string),
Stage: d.Get("stage").(string),
IncludedPermissions: convertStringSet(d.Get("permissions").(*schema.Set)),
},
}).Do()
if err != nil {
return fmt.Errorf("Error creating the custom organization role %s: %s", d.Get("title").(string), err)
}
d.SetId(role.Name)
} else {
return fmt.Errorf("Unable to verify whether custom org role %s already exists and must be undeleted: %v", roleId, err)
}
return resourceGoogleOrganizationIamCustomRoleRead(d, meta)
}
func resourceGoogleOrganizationIamCustomRoleRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
}
role, err := config.NewIamClient(userAgent).Organizations.Roles.Get(d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, d.Id())
}
parsedRoleName, err := ParseOrganizationCustomRoleName(role.Name)
if err != nil {
return err
}
if err := d.Set("role_id", parsedRoleName.Name); err != nil {
return fmt.Errorf("Error setting role_id: %s", err)
}
if err := d.Set("org_id", parsedRoleName.OrgId); err != nil {
return fmt.Errorf("Error setting org_id: %s", err)
}
if err := d.Set("title", role.Title); err != nil {
return fmt.Errorf("Error setting title: %s", err)
}
if err := d.Set("name", role.Name); err != nil {
return fmt.Errorf("Error setting name: %s", err)
}
if err := d.Set("description", role.Description); err != nil {
return fmt.Errorf("Error setting description: %s", err)
}
if err := d.Set("permissions", role.IncludedPermissions); err != nil {
return fmt.Errorf("Error setting permissions: %s", err)
}
if err := d.Set("stage", role.Stage); err != nil {
return fmt.Errorf("Error setting stage: %s", err)
}
if err := d.Set("deleted", role.Deleted); err != nil {
return fmt.Errorf("Error setting deleted: %s", err)
}
return nil
}
func resourceGoogleOrganizationIamCustomRoleUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
}
d.Partial(true)
// We want to update the role to some undeleted state.
// Make sure the role with given ID exists and is un-deleted before patching.
r, err := config.NewIamClient(userAgent).Organizations.Roles.Get(d.Id()).Do()
if err != nil {
return fmt.Errorf("unable to find custom project role %s to update: %v", d.Id(), err)
}
if r.Deleted {
_, err := config.NewIamClient(userAgent).Organizations.Roles.Undelete(d.Id(), &iam.UndeleteRoleRequest{}).Do()
if err != nil {
return fmt.Errorf("Error undeleting the custom organization role %s: %s", d.Get("title").(string), err)
}
}
if d.HasChange("title") || d.HasChange("description") || d.HasChange("stage") || d.HasChange("permissions") {
_, err := config.NewIamClient(userAgent).Organizations.Roles.Patch(d.Id(), &iam.Role{
Title: d.Get("title").(string),
Description: d.Get("description").(string),
Stage: d.Get("stage").(string),
IncludedPermissions: convertStringSet(d.Get("permissions").(*schema.Set)),
}).Do()
if err != nil {
return fmt.Errorf("Error updating the custom organization role %s: %s", d.Get("title").(string), err)
}
}
d.Partial(false)
return nil
}
func resourceGoogleOrganizationIamCustomRoleDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
}
r, err := config.NewIamClient(userAgent).Organizations.Roles.Get(d.Id()).Do()
if err == nil && r != nil && r.Deleted && d.Get("deleted").(bool) {
// This role has already been deleted, don't try again.
return nil
}
_, err = config.NewIamClient(userAgent).Organizations.Roles.Delete(d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting the custom organization role %s: %s", d.Get("title").(string), err)
}
return nil
}