diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl index 55c0db5d7916..0376d0c7acf4 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl @@ -200,6 +200,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_project": resourcemanager.DataSourceGoogleProject(), "google_projects": resourcemanager.DataSourceGoogleProjects(), "google_project_ancestry": resourcemanager.DataSourceGoogleProjectAncestry(), + "google_project_iam_custom_roles": resourcemanager.DataSourceGoogleProjectIamCustomRoles(), "google_project_organization_policy": resourcemanager.DataSourceGoogleProjectOrganizationPolicy(), "google_project_service": resourcemanager.DataSourceGoogleProjectService(), "google_pubsub_subscription": pubsub.DataSourceGooglePubsubSubscription(), diff --git a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles.go b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles.go new file mode 100644 index 000000000000..ea2b4441ff44 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles.go @@ -0,0 +1,146 @@ +package resourcemanager + +import ( + "context" + "fmt" + "path" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "google.golang.org/api/iam/v1" +) + +func DataSourceGoogleProjectIamCustomRoles() *schema.Resource { + return &schema.Resource{ + Read: dataSourceProjectIamCustomRoleRead, + Schema: map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Optional: true, + }, + "show_deleted": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "view": { + Type: schema.TypeString, + Optional: true, + Default: "BASIC", + ValidateFunc: validateView, + }, + "roles": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "deleted": { + Type: schema.TypeBool, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "permissions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "role_id": { + Type: schema.TypeString, + Computed: true, + }, + "stage": { + Type: schema.TypeString, + Computed: true, + }, + "title": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func validateView(val interface{}, key string) ([]string, []error) { + v := val.(string) + var errs []error + + if v != "BASIC" && v != "FULL" { + errs = append(errs, fmt.Errorf("%q must be either 'BASIC' or 'FULL', got %q", key, v)) + } + + return nil, errs +} + +func dataSourceProjectIamCustomRoleRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for custom roles: %s", err) + } + + roles := make([]map[string]interface{}, 0) + + showDeleted := d.Get("show_deleted").(bool) + view := d.Get("view").(string) + + request := config.NewIamClient(userAgent).Projects.Roles.List("projects/" + project).ShowDeleted(showDeleted).View(view) + + err = request.Pages(context.Background(), func(roleList *iam.ListRolesResponse) error { + for _, role := range roleList.Roles { + var permissions []string + + switch view { + case "BASIC": + permissions = []string{} + case "FULL": + permissions = role.IncludedPermissions + default: + return fmt.Errorf("Unsupported view type: %s", view) + } + + roles = append(roles, map[string]interface{}{ + "deleted": role.Deleted, + "description": role.Description, + "id": role.Name, + "name": role.Name, + "permissions": permissions, + "role_id": path.Base(role.Name), + "stage": role.Stage, + "title": role.Title, + }) + } + return nil + }) + + if err != nil { + return fmt.Errorf("Error retrieving project custom roles: %s", err) + } + + if err := d.Set("roles", roles); err != nil { + return fmt.Errorf("Error setting project custom roles: %s", err) + } + + d.SetId("projects/" + project) + + return nil +} diff --git a/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles_test.go b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles_test.go new file mode 100644 index 000000000000..b304bc5faaf2 --- /dev/null +++ b/mmv1/third_party/terraform/services/resourcemanager/data_source_google_project_iam_custom_roles_test.go @@ -0,0 +1,57 @@ +package resourcemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccDataSourceGoogleProjectIamCustomRoles_basic(t *testing.T) { + t.Parallel() + + project := envvar.GetTestProjectFromEnv() + roleId := "tfIamCustomRole" + acctest.RandString(t, 10) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccCheckGoogleProjectIamCustomRolesConfig(project, roleId), + Check: resource.ComposeTestCheckFunc( + // We can't guarantee no project won't have our custom role as first element, so we'll check set-ness rather than correctness + resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.id"), + resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.name"), + resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.role_id"), + resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.stage"), + resource.TestCheckResourceAttrSet("data.google_project_iam_custom_roles.this", "roles.0.title"), + ), + }, + }, + }) +} + +func testAccCheckGoogleProjectIamCustomRolesConfig(project string, roleId string) string { + return fmt.Sprintf(` +locals { + project = "%s" + role_id = "%s" +} +resource "google_project_iam_custom_role" "this" { + project = local.project + role_id = local.role_id + title = "Terraform Test" + permissions = [ + "iam.roles.create", + "iam.roles.delete", + "iam.roles.list", + ] +} +data "google_project_iam_custom_roles" "this" { + project = google_project_iam_custom_role.this.project +} +`, project, roleId) +} diff --git a/mmv1/third_party/terraform/website/docs/d/project_iam_custom_roles.html.markdown b/mmv1/third_party/terraform/website/docs/d/project_iam_custom_roles.html.markdown new file mode 100644 index 000000000000..ef2450c21d4f --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/project_iam_custom_roles.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Cloud Platform" +description: |- + Get information about Google Cloud IAM Custom Roles from a project. +--- + +# google_project_iam_custom_roles + +Get information about Google Cloud IAM Custom Roles from a project. +Note that you must have the `roles/iam.roleViewer`. +See [the official documentation](https://cloud.google.com/iam/docs/creating-custom-roles) +and [API](https://cloud.google.com/iam/docs/reference/rest/v1/projects.roles/list). + +```hcl +data "google_project_iam_custom_roles" "example" { + project = "your-project-id" + show_deleted = true + view = "FULL" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `project` - (Optional) The project were the custom role has been created in. Defaults to the provider project configuration. + +* `show_deleted` - (Optional) Include Roles that have been deleted. Defaults to `false`. + +* `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`. + +## Attributes Reference + +The following attributes are exported: + +* `roles` - A list of all retrieved custom roles roles. Structure is [defined below](#nested_roles). + +The `roles` block supports: + +* `deleted` - The current deleted state of the role. + +* `description` - A human-readable description for the role. + +* `id` - an identifier for the resource with the format `projects/{{project}}/roles/{{role_id}}`. + +* `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. + +* `permissions` - The names of the permissions this role grants when bound in an IAM policy. + +* `role_id` - The camel case role id used for this role. + +* `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). + +* `title` - A human-readable title for the role.