Skip to content

Commit 0fdfe63

Browse files
authored
Add data source for retrieving project iam custom roles (#13303)
1 parent 0b4149b commit 0fdfe63

File tree

4 files changed

+258
-0
lines changed

4 files changed

+258
-0
lines changed

mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl

+1
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ var handwrittenDatasources = map[string]*schema.Resource{
200200
"google_project": resourcemanager.DataSourceGoogleProject(),
201201
"google_projects": resourcemanager.DataSourceGoogleProjects(),
202202
"google_project_ancestry": resourcemanager.DataSourceGoogleProjectAncestry(),
203+
"google_project_iam_custom_roles": resourcemanager.DataSourceGoogleProjectIamCustomRoles(),
203204
"google_project_organization_policy": resourcemanager.DataSourceGoogleProjectOrganizationPolicy(),
204205
"google_project_service": resourcemanager.DataSourceGoogleProjectService(),
205206
"google_pubsub_subscription": pubsub.DataSourceGooglePubsubSubscription(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package resourcemanager
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"path"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
10+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
11+
"google.golang.org/api/iam/v1"
12+
)
13+
14+
func DataSourceGoogleProjectIamCustomRoles() *schema.Resource {
15+
return &schema.Resource{
16+
Read: dataSourceProjectIamCustomRoleRead,
17+
Schema: map[string]*schema.Schema{
18+
"project": {
19+
Type: schema.TypeString,
20+
Optional: true,
21+
},
22+
"show_deleted": {
23+
Type: schema.TypeBool,
24+
Optional: true,
25+
Default: false,
26+
},
27+
"view": {
28+
Type: schema.TypeString,
29+
Optional: true,
30+
Default: "BASIC",
31+
ValidateFunc: validateView,
32+
},
33+
"roles": {
34+
Type: schema.TypeList,
35+
Computed: true,
36+
Elem: &schema.Resource{
37+
Schema: map[string]*schema.Schema{
38+
"deleted": {
39+
Type: schema.TypeBool,
40+
Computed: true,
41+
},
42+
"description": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
},
46+
"id": {
47+
Type: schema.TypeString,
48+
Computed: true,
49+
},
50+
"name": {
51+
Type: schema.TypeString,
52+
Computed: true,
53+
},
54+
"permissions": {
55+
Type: schema.TypeList,
56+
Computed: true,
57+
Elem: &schema.Schema{Type: schema.TypeString},
58+
},
59+
"role_id": {
60+
Type: schema.TypeString,
61+
Computed: true,
62+
},
63+
"stage": {
64+
Type: schema.TypeString,
65+
Computed: true,
66+
},
67+
"title": {
68+
Type: schema.TypeString,
69+
Computed: true,
70+
},
71+
},
72+
},
73+
},
74+
},
75+
}
76+
}
77+
78+
func validateView(val interface{}, key string) ([]string, []error) {
79+
v := val.(string)
80+
var errs []error
81+
82+
if v != "BASIC" && v != "FULL" {
83+
errs = append(errs, fmt.Errorf("%q must be either 'BASIC' or 'FULL', got %q", key, v))
84+
}
85+
86+
return nil, errs
87+
}
88+
89+
func dataSourceProjectIamCustomRoleRead(d *schema.ResourceData, meta interface{}) error {
90+
config := meta.(*transport_tpg.Config)
91+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
92+
if err != nil {
93+
return err
94+
}
95+
96+
project, err := tpgresource.GetProject(d, config)
97+
if err != nil {
98+
return fmt.Errorf("Error fetching project for custom roles: %s", err)
99+
}
100+
101+
roles := make([]map[string]interface{}, 0)
102+
103+
showDeleted := d.Get("show_deleted").(bool)
104+
view := d.Get("view").(string)
105+
106+
request := config.NewIamClient(userAgent).Projects.Roles.List("projects/" + project).ShowDeleted(showDeleted).View(view)
107+
108+
err = request.Pages(context.Background(), func(roleList *iam.ListRolesResponse) error {
109+
for _, role := range roleList.Roles {
110+
var permissions []string
111+
112+
switch view {
113+
case "BASIC":
114+
permissions = []string{}
115+
case "FULL":
116+
permissions = role.IncludedPermissions
117+
default:
118+
return fmt.Errorf("Unsupported view type: %s", view)
119+
}
120+
121+
roles = append(roles, map[string]interface{}{
122+
"deleted": role.Deleted,
123+
"description": role.Description,
124+
"id": role.Name,
125+
"name": role.Name,
126+
"permissions": permissions,
127+
"role_id": path.Base(role.Name),
128+
"stage": role.Stage,
129+
"title": role.Title,
130+
})
131+
}
132+
return nil
133+
})
134+
135+
if err != nil {
136+
return fmt.Errorf("Error retrieving project custom roles: %s", err)
137+
}
138+
139+
if err := d.Set("roles", roles); err != nil {
140+
return fmt.Errorf("Error setting project custom roles: %s", err)
141+
}
142+
143+
d.SetId("projects/" + project)
144+
145+
return nil
146+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package resourcemanager_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/hashicorp/terraform-provider-google/google/acctest"
9+
"github.com/hashicorp/terraform-provider-google/google/envvar"
10+
)
11+
12+
func TestAccDataSourceGoogleProjectIamCustomRoles_basic(t *testing.T) {
13+
t.Parallel()
14+
15+
project := envvar.GetTestProjectFromEnv()
16+
roleId := "tfIamCustomRole" + acctest.RandString(t, 10)
17+
18+
acctest.VcrTest(t, resource.TestCase{
19+
PreCheck: func() { acctest.AccTestPreCheck(t) },
20+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
21+
Steps: []resource.TestStep{
22+
{
23+
Config: testAccCheckGoogleProjectIamCustomRolesConfig(project, roleId),
24+
Check: resource.ComposeTestCheckFunc(
25+
// We can't guarantee no project won't have our custom role as first element, so we'll check set-ness rather than correctness
26+
resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.id"),
27+
resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.name"),
28+
resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.role_id"),
29+
resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.stage"),
30+
resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.title"),
31+
),
32+
},
33+
},
34+
})
35+
}
36+
37+
func testAccCheckGoogleProjectIamCustomRolesConfig(project string, roleId string) string {
38+
return fmt.Sprintf(`
39+
locals {
40+
project = "%s"
41+
role_id = "%s"
42+
}
43+
resource "google_project_iam_custom_role" "this" {
44+
project = local.project
45+
role_id = local.role_id
46+
title = "Terraform Test"
47+
permissions = [
48+
"iam.roles.create",
49+
"iam.roles.delete",
50+
"iam.roles.list",
51+
]
52+
}
53+
data "google_project_iam_custom_roles" "this" {
54+
project = google_project_iam_custom_role.this.project
55+
}
56+
`, project, roleId)
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
subcategory: "Cloud Platform"
3+
description: |-
4+
Get information about Google Cloud IAM Custom Roles from a project.
5+
---
6+
7+
# google_project_iam_custom_roles
8+
9+
Get information about Google Cloud IAM Custom Roles from a project.
10+
Note that you must have the `roles/iam.roleViewer`.
11+
See [the official documentation](https://cloud.google.com/iam/docs/creating-custom-roles)
12+
and [API](https://cloud.google.com/iam/docs/reference/rest/v1/projects.roles/list).
13+
14+
```hcl
15+
data "google_project_iam_custom_roles" "example" {
16+
project = "your-project-id"
17+
show_deleted = true
18+
view = "FULL"
19+
}
20+
```
21+
22+
## Argument Reference
23+
24+
The following arguments are supported:
25+
26+
* `project` - (Optional) The project were the custom role has been created in. Defaults to the provider project configuration.
27+
28+
* `show_deleted` - (Optional) Include Roles that have been deleted. Defaults to `false`.
29+
30+
* `view` - (Optional) When `"FULL"` is specified, the `permissions` field is returned, which includes a list of all permissions in the role. The default value is `"BASIC"`, which does not return the `permissions`.
31+
32+
## Attributes Reference
33+
34+
The following attributes are exported:
35+
36+
* `roles` - A list of all retrieved custom roles roles. Structure is [defined below](#nested_roles).
37+
38+
<a name="nested_roles"></a>The `roles` block supports:
39+
40+
* `deleted` - The current deleted state of the role.
41+
42+
* `description` - A human-readable description for the role.
43+
44+
* `id` - an identifier for the resource with the format `projects/{{project}}/roles/{{role_id}}`.
45+
46+
* `name` - The name of the role in the format `projects/{{project}}/roles/{{role_id}}`. Like `id`, this field can be used as a reference in other resources such as IAM role bindings.
47+
48+
* `permissions` - The names of the permissions this role grants when bound in an IAM policy.
49+
50+
* `role_id` - The camel case role id used for this role.
51+
52+
* `stage` - The current launch stage of the role. List of possible stages is [here](https://cloud.google.com/iam/reference/rest/v1/organizations.roles#Role.RoleLaunchStage).
53+
54+
* `title` - A human-readable title for the role.

0 commit comments

Comments
 (0)