mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-03 01:01:06 +00:00
Add new resource to support IAM custom project roles. (#709)
* Upgrade iam client to latest version * Add new resource to support IAM custom roles. * Add documentation
This commit is contained in:
parent
756dec44d8
commit
ab68b06af5
29
google/import_google_project_iam_custom_role_test.go
Normal file
29
google/import_google_project_iam_custom_role_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccGoogleProjectIamCustomRole_import(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
roleId := "tfIamRole" + acctest.RandString(10)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectIamCustomRoleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_update(roleId),
|
||||
},
|
||||
{
|
||||
ResourceName: "google_project_iam_custom_role.foo",
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
@ -130,6 +130,7 @@ func Provider() terraform.ResourceProvider {
|
||||
"google_project_iam_binding": resourceGoogleProjectIamBinding(),
|
||||
"google_project_iam_member": resourceGoogleProjectIamMember(),
|
||||
"google_project_service": resourceGoogleProjectService(),
|
||||
"google_project_iam_custom_role": resourceGoogleProjectIamCustomRole(),
|
||||
"google_project_services": resourceGoogleProjectServices(),
|
||||
"google_pubsub_topic": resourcePubsubTopic(),
|
||||
"google_pubsub_subscription": resourcePubsubSubscription(),
|
||||
|
170
google/resource_google_project_iam_custom_role.go
Normal file
170
google/resource_google_project_iam_custom_role.go
Normal file
@ -0,0 +1,170 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/helper/validation"
|
||||
"google.golang.org/api/iam/v1"
|
||||
)
|
||||
|
||||
func resourceGoogleProjectIamCustomRole() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceGoogleProjectIamCustomRoleCreate,
|
||||
Read: resourceGoogleProjectIamCustomRoleRead,
|
||||
Update: resourceGoogleProjectIamCustomRoleUpdate,
|
||||
Delete: resourceGoogleProjectIamCustomRoleDelete,
|
||||
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"role_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"title": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"permissions": {
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
MinItems: 1,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"project": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"stage": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "GA",
|
||||
ValidateFunc: validation.StringInSlice([]string{"ALPHA", "BETA", "GA", "DEPRECATED", "DISABLED", "EAP"}, false),
|
||||
},
|
||||
"description": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"deleted": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceGoogleProjectIamCustomRoleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Get("deleted").(bool) {
|
||||
return fmt.Errorf("Cannot create a custom project role with a deleted state. `deleted` field should be false.")
|
||||
}
|
||||
|
||||
role, err := config.clientIAM.Projects.Roles.Create("projects/"+project, &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 project role %s: %s", d.Get("title").(string), err)
|
||||
}
|
||||
|
||||
d.SetId(role.Name)
|
||||
|
||||
return resourceGoogleProjectIamCustomRoleRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceGoogleProjectIamCustomRoleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
role, err := config.clientIAM.Projects.Roles.Get(d.Id()).Do()
|
||||
if err != nil {
|
||||
return handleNotFoundError(err, d, d.Id())
|
||||
}
|
||||
|
||||
d.Set("role_id", GetResourceNameFromSelfLink(role.Name))
|
||||
d.Set("title", role.Title)
|
||||
d.Set("description", role.Description)
|
||||
d.Set("permissions", role.IncludedPermissions)
|
||||
d.Set("stage", role.Stage)
|
||||
d.Set("deleted", role.Deleted)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceGoogleProjectIamCustomRoleUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
d.Partial(true)
|
||||
|
||||
if d.HasChange("deleted") {
|
||||
if d.Get("deleted").(bool) {
|
||||
if err := resourceGoogleProjectIamCustomRoleDelete(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := resourceGoogleProjectIamCustomRoleUndelete(d, meta); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.SetPartial("deleted")
|
||||
}
|
||||
|
||||
if d.HasChange("title") || d.HasChange("description") || d.HasChange("stage") || d.HasChange("permissions") {
|
||||
_, err := config.clientIAM.Projects.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 project role %s: %s", d.Get("title").(string), err)
|
||||
}
|
||||
d.SetPartial("title")
|
||||
d.SetPartial("description")
|
||||
d.SetPartial("stage")
|
||||
d.SetPartial("permissions")
|
||||
}
|
||||
|
||||
d.Partial(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceGoogleProjectIamCustomRoleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
_, err := config.clientIAM.Projects.Roles.Delete(d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting the custom project role %s: %s", d.Get("title").(string), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceGoogleProjectIamCustomRoleUndelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
_, err := config.clientIAM.Projects.Roles.Undelete(d.Id(), &iam.UndeleteRoleRequest{}).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error undeleting the custom project role %s: %s", d.Get("title").(string), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
195
google/resource_google_project_iam_custom_role_test.go
Normal file
195
google/resource_google_project_iam_custom_role_test.go
Normal file
@ -0,0 +1,195 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccGoogleProjectIamCustomRole_basic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
roleId := "tfIamCustomRole" + acctest.RandString(10)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectIamCustomRoleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
|
||||
Check: testAccCheckGoogleProjectIamCustomRole(
|
||||
"google_project_iam_custom_role.foo",
|
||||
"My Custom Role",
|
||||
"foo",
|
||||
"GA",
|
||||
[]string{"iam.roles.list"}),
|
||||
},
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_update(roleId),
|
||||
Check: testAccCheckGoogleProjectIamCustomRole(
|
||||
"google_project_iam_custom_role.foo",
|
||||
"My Custom Role Updated",
|
||||
"bar",
|
||||
"BETA",
|
||||
[]string{"iam.roles.list", "iam.roles.create", "iam.roles.delete"}),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccGoogleProjectIamCustomRole_undelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
roleId := "tfIamCustomRole" + acctest.RandString(10)
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckGoogleProjectIamCustomRoleDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
|
||||
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", false),
|
||||
},
|
||||
// Soft-delete
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_deleted(roleId),
|
||||
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", true),
|
||||
},
|
||||
// Undelete
|
||||
{
|
||||
Config: testAccCheckGoogleProjectIamCustomRole_basic(roleId),
|
||||
Check: testAccCheckGoogleProjectIamCustomRoleDeletionStatus("google_project_iam_custom_role.foo", false),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRoleDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_project_iam_custom_role" {
|
||||
continue
|
||||
}
|
||||
|
||||
role, err := config.clientIAM.Projects.Roles.Get(rs.Primary.ID).Do()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !role.Deleted {
|
||||
return fmt.Errorf("Iam custom role still exists")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRole(n, title, description, stage string, permissions []string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
role, err := config.clientIAM.Projects.Roles.Get(rs.Primary.ID).Do()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if title != role.Title {
|
||||
return fmt.Errorf("Incorrect title. Expected %q, got %q", title, role.Title)
|
||||
}
|
||||
|
||||
if description != role.Description {
|
||||
return fmt.Errorf("Incorrect description. Expected %q, got %q", description, role.Description)
|
||||
}
|
||||
|
||||
if stage != role.Stage {
|
||||
return fmt.Errorf("Incorrect stage. Expected %q, got %q", stage, role.Stage)
|
||||
}
|
||||
|
||||
sort.Strings(permissions)
|
||||
sort.Strings(role.IncludedPermissions)
|
||||
if !reflect.DeepEqual(permissions, role.IncludedPermissions) {
|
||||
return fmt.Errorf("Incorrect permissions. Expected %q, got %q", permissions, role.IncludedPermissions)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRoleDeletionStatus(n string, deleted bool) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
role, err := config.clientIAM.Projects.Roles.Get(rs.Primary.ID).Do()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if deleted != role.Deleted {
|
||||
return fmt.Errorf("Incorrect deletion status. Expected %t, got %t", deleted, role.Deleted)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRole_basic(roleId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project_iam_custom_role" "foo" {
|
||||
role_id = "%s"
|
||||
title = "My Custom Role"
|
||||
description = "foo"
|
||||
permissions = ["iam.roles.list"]
|
||||
}
|
||||
`, roleId)
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRole_deleted(roleId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project_iam_custom_role" "foo" {
|
||||
role_id = "%s"
|
||||
title = "My Custom Role"
|
||||
description = "foo"
|
||||
permissions = ["iam.roles.list"]
|
||||
deleted = true
|
||||
}
|
||||
`, roleId)
|
||||
}
|
||||
|
||||
func testAccCheckGoogleProjectIamCustomRole_update(roleId string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_project_iam_custom_role" "foo" {
|
||||
role_id = "%s"
|
||||
title = "My Custom Role Updated"
|
||||
description = "bar"
|
||||
permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
|
||||
stage = "BETA"
|
||||
}
|
||||
`, roleId)
|
||||
}
|
2481
vendor/google.golang.org/api/iam/v1/iam-api.json
generated
vendored
2481
vendor/google.golang.org/api/iam/v1/iam-api.json
generated
vendored
File diff suppressed because it is too large
Load Diff
3548
vendor/google.golang.org/api/iam/v1/iam-gen.go
generated
vendored
3548
vendor/google.golang.org/api/iam/v1/iam-gen.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -1115,10 +1115,10 @@
|
||||
"revisionTime": "2017-06-08T21:27:40Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "+u3FeHSXeRJZzw52OZsT3wUPb24=",
|
||||
"checksumSHA1": "80I5aL8rBaTYQ2SScpc1MYRz5wY=",
|
||||
"path": "google.golang.org/api/iam/v1",
|
||||
"revision": "3cc2e591b550923a2c5f0ab5a803feda924d5823",
|
||||
"revisionTime": "2016-11-27T23:54:21Z"
|
||||
"revision": "76b09a3314405551b1f19de9944347fcda3f80ae",
|
||||
"revisionTime": "2017-11-08T00:03:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "dENAVft6XToomTHrm5J2zFt4hgU=",
|
||||
|
56
website/docs/r/google_project_iam_role.html.markdown
Normal file
56
website/docs/r/google_project_iam_role.html.markdown
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_project_iam_custom_role"
|
||||
sidebar_current: "docs-google-project-iam-custom-role"
|
||||
description: |-
|
||||
Allows management of a customized Cloud IAM project role.
|
||||
---
|
||||
|
||||
# google\_project\_iam\_custom\_role
|
||||
|
||||
Allows management of a customized Cloud IAM project role. For more information see
|
||||
[the official documentation](https://cloud.google.com/iam/docs/understanding-custom-roles)
|
||||
and
|
||||
[API](https://cloud.google.com/iam/reference/rest/v1/projects.roles).
|
||||
|
||||
## Example Usage
|
||||
|
||||
This snippet creates a customized IAM role.
|
||||
|
||||
```hcl
|
||||
resource "google_project_iam_custom_role" "my-custom-role" {
|
||||
role_id = "myCustomRole"
|
||||
title = "My Custom Role"
|
||||
description = "A description"
|
||||
permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `role_id` - (Required) The role id to use for this role.
|
||||
|
||||
* `title` - (Required) A human-readable title for the role.
|
||||
|
||||
* `permissions` (Required) The names of the permissions this role grants when bound in an IAM policy. At least one permission must be specified.
|
||||
|
||||
* `project` - (Optional) The project that the service account will be created in.
|
||||
Defaults to the provider project configuration.
|
||||
|
||||
* `stage` - (Optional) The current launch stage of the role.
|
||||
Defaults to `GA`.
|
||||
List of possible stages is [here](https://cloud.google.com/iam/reference/rest/v1/organizations.roles#Role.RoleLaunchStage).
|
||||
|
||||
* `description` - (Optional) A human-readable description for the role.
|
||||
|
||||
* `deleted` - (Optional) The current deleted state of the role. Defaults to `false`.
|
||||
|
||||
## Import
|
||||
|
||||
Customized IAM project role can be imported using their URI, e.g.
|
||||
|
||||
```
|
||||
$ terraform import google_project_iam_custom_role.my-custom-role projects/my-project/roles/myCustomRole
|
||||
```
|
@ -95,6 +95,9 @@
|
||||
<li<%= sidebar_current("docs-google-project-iam-policy") %>>
|
||||
<a href="/docs/providers/google/r/google_project_iam_policy.html">google_project_iam_policy</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-project-iam-custom-role") %>>
|
||||
<a href="/docs/providers/google/r/google_project_iam_custom_role.html">google_project_iam_custom_role</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-google-project-service") %>>
|
||||
<a href="/docs/providers/google/r/google_project_service.html">google_project_service</a>
|
||||
</li>
|
||||
|
Loading…
Reference in New Issue
Block a user