Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add role assignment resource #265

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions openstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ func Provider() terraform.ResourceProvider {
"openstack_fw_rule_v1": resourceFWRuleV1(),
"openstack_identity_project_v3": resourceIdentityProjectV3(),
"openstack_identity_role_v3": resourceIdentityRoleV3(),
"openstack_identity_role_assignment_v3": resourceIdentityRoleAssignmentV3(),
"openstack_identity_user_v3": resourceIdentityUserV3(),
"openstack_images_image_v2": resourceImagesImageV2(),
"openstack_lb_member_v1": resourceLBMemberV1(),
Expand Down
178 changes: 178 additions & 0 deletions openstack/resource_openstack_identity_role_assignment_v3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package openstack

import (
"fmt"
"log"

"strings"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/identity/v3/roles"
"github.com/gophercloud/gophercloud/pagination"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceIdentityRoleAssignmentV3() *schema.Resource {
return &schema.Resource{
Create: resourceIdentityRoleAssignmentV3Create,
Read: resourceIdentityRoleAssignmentV3Read,
Delete: resourceIdentityRoleAssignmentV3Delete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"domain_id": &schema.Schema{
Type: schema.TypeString,
ConflictsWith: []string{"project_id"},
Optional: true,
ForceNew: true,
},

"group_id": &schema.Schema{
Type: schema.TypeString,
ConflictsWith: []string{"user_id"},
Optional: true,
ForceNew: true,
},

"project_id": &schema.Schema{
Type: schema.TypeString,
ConflictsWith: []string{"domain_id"},
Optional: true,
ForceNew: true,
},

"role_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"user_id": &schema.Schema{
Type: schema.TypeString,
ConflictsWith: []string{"group_id"},
Optional: true,
ForceNew: true,
},
},
}
}

func resourceIdentityRoleAssignmentV3Create(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
identityClient, err := config.identityV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating OpenStack identity client: %s", err)
}

domainID := d.Get("domain_id").(string)
groupID := d.Get("group_id").(string)
projectID := d.Get("project_id").(string)
roleID := d.Get("role_id").(string)
userID := d.Get("user_id").(string)
opts := roles.AssignOpts{
DomainID: domainID,
GroupID: groupID,
ProjectID: projectID,
UserID: userID,
}

err = roles.Assign(identityClient, roleID, opts).ExtractErr()
if err != nil {
return fmt.Errorf("Error assigning role: %s", err)
}

d.SetId(buildRoleAssignmentID(domainID, projectID, groupID, userID, roleID))

return resourceIdentityRoleAssignmentV3Read(d, meta)
}

func resourceIdentityRoleAssignmentV3Read(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
identityClient, err := config.identityV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating OpenStack identity client: %s", err)
}

roleAssignment, err := getRoleAssignment(identityClient, d)
if err != nil {
return fmt.Errorf("Error getting role assignment: %s", err)
}

log.Printf("[DEBUG] Retrieved OpenStack role assignment: %#v", roleAssignment)
d.Set("domain_id", roleAssignment.Scope.Domain.ID)
d.Set("project_id", roleAssignment.Scope.Project.ID)
d.Set("group_id", roleAssignment.Group.ID)
d.Set("user_id", roleAssignment.User.ID)
d.Set("role_id", roleAssignment.Role.ID)
d.Set("region", GetRegion(d, config))

return nil
}

func resourceIdentityRoleAssignmentV3Delete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
identityClient, err := config.identityV3Client(GetRegion(d, config))
if err != nil {
return fmt.Errorf("Error creating OpenStack identity client: %s", err)
}

domainID, projectID, groupID, userID, roleID := extractRoleAssignmentID(d.Id())
var opts roles.UnassignOpts
opts = roles.UnassignOpts{
DomainID: domainID,
GroupID: groupID,
ProjectID: projectID,
UserID: userID,
}
roles.Unassign(identityClient, roleID, opts).ExtractErr()
if err != nil {
return fmt.Errorf("Error unassigning role: %s", err)
}

return nil
}

func getRoleAssignment(identityClient *gophercloud.ServiceClient, d *schema.ResourceData) (roles.RoleAssignment, error) {
domainID, projectID, groupID, userID, roleID := extractRoleAssignmentID(d.Id())

var opts roles.ListAssignmentsOpts
opts = roles.ListAssignmentsOpts{
GroupID: groupID,
ScopeDomainID: domainID,
ScopeProjectID: projectID,
UserID: userID,
}

pager := roles.ListAssignments(identityClient, opts)
var assignment roles.RoleAssignment

err := pager.EachPage(func(page pagination.Page) (bool, error) {
assignmentList, err := roles.ExtractRoleAssignments(page)
if err != nil {
return false, err
}

for _, a := range assignmentList {
if a.Role.ID == roleID {
assignment = a
return false, nil
}
}

return true, nil
})

return assignment, err
}

// Role assignments have no ID in OpenStack. Build an ID out of the IDs that make up the role assignment
func buildRoleAssignmentID(domainID, projectID, groupID, userID, roleID string) string {
return fmt.Sprintf("%s/%s/%s/%s/%s", domainID, projectID, groupID, userID, roleID)
}

func extractRoleAssignmentID(roleAssignmentID string) (string, string, string, string, string) {
split := strings.Split(roleAssignmentID, "/")
return split[0], split[1], split[2], split[3], split[4]
}
155 changes: 155 additions & 0 deletions openstack/resource_openstack_identity_role_assignment_v3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package openstack

import (
"fmt"
"testing"

"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"

"github.com/gophercloud/gophercloud/pagination"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"

"github.com/gophercloud/gophercloud/openstack/identity/v3/roles"
"github.com/gophercloud/gophercloud/openstack/identity/v3/users"
)

func TestAccIdentityV3RoleAssignment_basic(t *testing.T) {
var role roles.Role
var user users.User
var project projects.Project
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAdminOnly(t)
},
Providers: testAccProviders,
CheckDestroy: testAccCheckIdentityV3RoleAssignmentDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccIdentityV3RoleAssignment_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckIdentityV3RoleAssignmentExists("openstack_identity_role_assignment_v3.role_assignment_1", &role, &user, &project),
resource.TestCheckResourceAttrPtr(
"openstack_identity_role_assignment_v3.role_assignment_1", "project_id", &project.ID),
resource.TestCheckResourceAttrPtr(
"openstack_identity_role_assignment_v3.role_assignment_1", "user_id", &user.ID),
resource.TestCheckResourceAttrPtr(
"openstack_identity_role_assignment_v3.role_assignment_1", "role_id", &role.ID),
),
},
},
})
}

func testAccCheckIdentityV3RoleAssignmentDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
identityClient, err := config.identityV3Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating OpenStack identity client: %s", err)
}

for _, rs := range s.RootModule().Resources {
if rs.Type != "openstack_identity_role_assignment_v3" {
continue
}

_, err := roles.Get(identityClient, rs.Primary.ID).Extract()
if err == nil {
return fmt.Errorf("Role assignment still exists")
}
}

return nil
}

func testAccCheckIdentityV3RoleAssignmentExists(n string, role *roles.Role, user *users.User, project *projects.Project) 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)
identityClient, err := config.identityV3Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating OpenStack identity client: %s", err)
}

domainID, projectID, groupID, userID, roleID := extractRoleAssignmentID(rs.Primary.ID)

var opts roles.ListAssignmentsOpts
opts = roles.ListAssignmentsOpts{
GroupID: groupID,
ScopeDomainID: domainID,
ScopeProjectID: projectID,
UserID: userID,
}

pager := roles.ListAssignments(identityClient, opts)
var assignment roles.RoleAssignment

err = pager.EachPage(func(page pagination.Page) (bool, error) {
assignmentList, err := roles.ExtractRoleAssignments(page)
if err != nil {
return false, err
}

for _, a := range assignmentList {
if a.Role.ID == roleID {
assignment = a
return false, nil
}
}

return true, nil
})
if err != nil {
return err
}

p, err := projects.Get(identityClient, assignment.Scope.Project.ID).Extract()
if err != nil {
return fmt.Errorf("Project not found")
}
*project = *p
u, err := users.Get(identityClient, assignment.User.ID).Extract()
if err != nil {
return fmt.Errorf("User not found")
}
*user = *u
r, err := roles.Get(identityClient, assignment.Role.ID).Extract()
if err != nil {
return fmt.Errorf("Role not found")
}
*role = *r

return nil
}
}

const testAccIdentityV3RoleAssignment_basic = `
resource "openstack_identity_project_v3" "project_1" {
name = "project_1"
}

resource "openstack_identity_user_v3" "user_1" {
name = "user_1"
default_project_id = "${openstack_identity_project_v3.project_1.id}"
}

resource "openstack_identity_role_v3" "role_1" {
name = "role_1"
}

resource "openstack_identity_role_assignment_v3" "role_assignment_1" {
user_id = "${openstack_identity_user_v3.user_1.id}"
project_id = "${openstack_identity_project_v3.project_1.id}"
role_id = "${openstack_identity_role_v3.role_1.id}"
}
`
Loading