Add principles to roles (#12)

* feat: add principle to role resource

* docs: add principle usage to role resource
This commit is contained in:
Jeff Malnick authored and GitHub committed 2020-07-10 15:32:44 -07:00
1 parent d6c7675950
commit 13e3638dd6
5 files changed
+373 -30

No files matched your search

+91 -28
View File
@@ -11,6 +11,9 @@ import (
const (
roleNameKey = "name"
roleDescriptionKey = "description"
roleUsersKey = "users"
roleGroupsKey = "groups"
roleGrantsKey = "grants"
)
func resourceRole() *schema.Resource {
@@ -28,6 +31,16 @@ func resourceRole() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
roleUsersKey: {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
roleGroupsKey: {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
@@ -47,6 +60,18 @@ func convertRoleToResourceData(u *roles.Role, d *schema.ResourceData) error {
}
}
if u.UserIds != nil {
if err := d.Set(roleUsersKey, u.UserIds); err != nil {
return err
}
}
if u.GroupIds != nil {
if err := d.Set(roleGroupsKey, u.GroupIds); err != nil {
return err
}
}
d.SetId(u.Id)
return nil
@@ -63,6 +88,18 @@ func convertResourceDataToRole(d *schema.ResourceData) *roles.Role {
name := nameVal.(string)
u.Name = &name
}
if val, ok := d.GetOk(roleGroupsKey); ok {
groupIds := val.(*schema.Set).List()
for _, i := range groupIds {
u.GroupIds = append(u.GroupIds, i.(string))
}
}
if val, ok := d.GetOk(roleUsersKey); ok {
userIds := val.(*schema.Set).List()
for _, i := range userIds {
u.UserIds = append(u.UserIds, i.(string))
}
}
if d.Id() != "" {
u.Id = d.Id()
@@ -80,17 +117,23 @@ func resourceRoleCreate(d *schema.ResourceData, meta interface{}) error {
Client: client,
}
u := convertResourceDataToRole(d)
r := convertResourceDataToRole(d)
users := r.UserIds
groups := r.GroupIds
u, apiErr, err := o.CreateRole(ctx, u)
if err != nil {
return fmt.Errorf("error calling new role: %s", err.Error())
}
if apiErr != nil {
return fmt.Errorf("error creating role: %s", *apiErr.Message)
r, apiErr, err := o.CreateRole(ctx, r)
if apiErr != nil || err != nil {
return fmt.Errorf("error creating role:\n API Err: %v\n Err: %v\n", *apiErr.Message, err)
}
d.SetId(u.Id)
if len(users) > 0 || len(groups) > 0 {
r, apiErr, err = r.SetPrincipals(ctx, groups, users)
if apiErr != nil || err != nil {
return fmt.Errorf("error setting principle on role:\n API Err: %+v\n Err: %+v\n", *apiErr.Message, err)
}
}
d.SetId(r.Id)
return nil
}
@@ -104,9 +147,9 @@ func resourceRoleRead(d *schema.ResourceData, meta interface{}) error {
Client: client,
}
u := convertResourceDataToRole(d)
r := convertResourceDataToRole(d)
u, apiErr, err := o.ReadRole(ctx, u)
r, apiErr, err := o.ReadRole(ctx, r)
if err != nil {
return fmt.Errorf("error reading role: %s", err.Error())
}
@@ -114,7 +157,7 @@ func resourceRoleRead(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("error reading role: %s", *apiErr.Message)
}
return convertRoleToResourceData(u, d)
return convertRoleToResourceData(r, d)
}
func resourceRoleUpdate(d *schema.ResourceData, meta interface{}) error {
@@ -126,27 +169,50 @@ func resourceRoleUpdate(d *schema.ResourceData, meta interface{}) error {
Client: client,
}
u := convertResourceDataToRole(d)
r := convertResourceDataToRole(d)
if d.HasChange(roleNameKey) {
n := d.Get(roleNameKey).(string)
u.Name = &n
r.Name = &n
}
if d.HasChange(roleDescriptionKey) {
d := d.Get(roleDescriptionKey).(string)
u.Description = &d
r.Description = &d
}
u, apiErr, err := o.UpdateRole(ctx, u)
if err != nil {
return err
}
if apiErr != nil {
return fmt.Errorf("error updating role: %s\n Invalid request fields: %v\n", *apiErr.Message, apiErr.Details.RequestFields)
r.GroupIds = nil
r.UserIds = nil
r, apiErr, err := o.UpdateRole(ctx, r)
if apiErr != nil || err != nil {
return fmt.Errorf("error updating role:\n API Err: %v\n Err: %v\n", *apiErr.Message, err)
}
return convertRoleToResourceData(u, d)
userIDs := []string{}
if d.HasChange(roleUsersKey) {
users := d.Get(roleUsersKey).(*schema.Set).List()
for _, user := range users {
userIDs = append(userIDs, user.(string))
}
}
groupIDs := []string{}
if d.HasChange(roleGroupsKey) {
groups := d.Get(roleGroupsKey).(*schema.Set).List()
for _, group := range groups {
groupIDs = append(groupIDs, group.(string))
}
}
if d.HasChange(roleGroupsKey) || d.HasChange(roleUsersKey) {
r, apiErr, err = r.SetPrincipals(ctx, groupIDs, userIDs)
if apiErr != nil || err != nil {
return fmt.Errorf("error updating principle on role:\n API Err: %v\n Err: %v\n", *apiErr.Message, err)
}
}
return convertRoleToResourceData(r, d)
}
func resourceRoleDelete(d *schema.ResourceData, meta interface{}) error {
@@ -158,14 +224,11 @@ func resourceRoleDelete(d *schema.ResourceData, meta interface{}) error {
Client: client,
}
u := convertResourceDataToRole(d)
r := convertResourceDataToRole(d)
_, apiErr, err := o.DeleteRole(ctx, u)
if err != nil {
return fmt.Errorf("error deleting role: %s", err.Error())
}
if apiErr != nil {
return fmt.Errorf("error deleting role: %s", *apiErr.Message)
_, apiErr, err := o.DeleteRole(ctx, r)
if apiErr != nil || err != nil {
return fmt.Errorf("error deleting role:\n API Err: %v\n Err: %v\n", *apiErr.Message, err)
}
return nil
+251
View File
@@ -31,8 +31,130 @@ resource "watchtower_role" "foo" {
name = "test"
description = "%s"
}`, fooRoleDescriptionUpdate)
fooRoleWithUser = `
resource "watchtower_user" "foo" {
name = "foo"
}
resource "watchtower_role" "foo" {
name = "test"
description = "test description"
users = [watchtower_user.foo.id]
}`
fooRoleWithUserUpdate = `
resource "watchtower_user" "foo" {
name = "foo"
}
resource "watchtower_user" "bar" {
name = "bar"
}
resource "watchtower_role" "foo" {
name = "test"
description = "test description"
users = [watchtower_user.foo.id, watchtower_user.bar.id]
}`
fooRoleWithGroups = `
resource "watchtower_group" "foo" {
name = "foo"
}
resource "watchtower_role" "foo" {
name = "test"
description = "test description"
groups = [watchtower_group.foo.id]
}`
fooRoleWithGroupsUpdate = `
resource "watchtower_group" "foo" {
name = "foo"
}
resource "watchtower_group" "bar" {
name = "bar"
}
resource "watchtower_role" "foo" {
name = "test"
description = "test description"
groups = [watchtower_group.foo.id, watchtower_group.bar.id]
}`
)
func TestAccRoleWithUsers(t *testing.T) {
tc := controller.NewTestController(t, controller.WithDefaultOrgId("o_0000000000"))
defer tc.Shutdown()
url := tc.ApiAddrs()[0]
resource.Test(t, resource.TestCase{
Providers: testProviders,
CheckDestroy: testAccCheckRoleResourceDestroy(t),
Steps: []resource.TestStep{
{
// test create
Config: testConfig(url, fooRoleWithUser),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists("watchtower_role.foo"),
testAccCheckRoleResourceUsersSet("watchtower_role.foo", []string{"watchtower_user.foo"}),
testAccCheckUserResourceExists("watchtower_user.foo"),
resource.TestCheckResourceAttr("watchtower_role.foo", roleDescriptionKey, "test description"),
resource.TestCheckResourceAttr("watchtower_role.foo", roleNameKey, "test"),
resource.TestCheckResourceAttr("watchtower_user.foo", "name", "foo"),
),
},
{
// test update
Config: testConfig(url, fooRoleWithUserUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists("watchtower_role.foo"),
testAccCheckUserResourceExists("watchtower_user.foo"),
testAccCheckUserResourceExists("watchtower_user.bar"),
testAccCheckRoleResourceUsersSet("watchtower_role.foo", []string{"watchtower_user.foo", "watchtower_user.bar"}),
),
},
},
})
}
func TestAccRoleWithGroups(t *testing.T) {
tc := controller.NewTestController(t, controller.WithDefaultOrgId("o_0000000000"))
defer tc.Shutdown()
url := tc.ApiAddrs()[0]
resource.Test(t, resource.TestCase{
Providers: testProviders,
CheckDestroy: testAccCheckRoleResourceDestroy(t),
Steps: []resource.TestStep{
{
// test create
Config: testConfig(url, fooRoleWithGroups),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists("watchtower_role.foo"),
testAccCheckRoleResourceGroupsSet("watchtower_role.foo", []string{"watchtower_group.foo"}),
testAccCheckUserResourceExists("watchtower_group.foo"),
resource.TestCheckResourceAttr("watchtower_role.foo", roleDescriptionKey, "test description"),
resource.TestCheckResourceAttr("watchtower_role.foo", roleNameKey, "test"),
resource.TestCheckResourceAttr("watchtower_group.foo", "name", "foo"),
),
},
{
// test update
Config: testConfig(url, fooRoleWithGroupsUpdate),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoleResourceExists("watchtower_role.foo"),
testAccCheckUserResourceExists("watchtower_group.foo"),
testAccCheckUserResourceExists("watchtower_group.bar"),
testAccCheckRoleResourceGroupsSet("watchtower_role.foo", []string{"watchtower_group.foo", "watchtower_group.bar"}),
),
},
},
})
}
func TestAccRole(t *testing.T) {
tc := controller.NewTestController(t, controller.WithDefaultOrgId("o_0000000000"))
defer tc.Shutdown()
@@ -139,6 +261,131 @@ func testAccCheckRoleResourceExists(name string) resource.TestCheckFunc {
}
}
func testAccCheckRoleResourceUsersSet(name string, users []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("role resource not found: %s", name)
}
id := rs.Primary.ID
if id == "" {
return fmt.Errorf("role resource ID is not set")
}
userIDs := []string{}
for _, userResourceName := range users {
ur, ok := s.RootModule().Resources[userResourceName]
if !ok {
return fmt.Errorf("user resource not found: %s", userResourceName)
}
userID := ur.Primary.ID
if id == "" {
return fmt.Errorf("user resource ID not set")
}
userIDs = append(userIDs, userID)
}
md := testProvider.Meta().(*metaData)
u := roles.Role{Id: id}
o := &scopes.Organization{
Client: md.client,
}
r, _, err := o.ReadRole(md.ctx, &u)
if err != nil {
return fmt.Errorf("Got an error when reading role %q: %v", id, err)
}
// for every user set as a principle on the role in the state, ensure
// each role in watchtower has the same setings
if len(r.UserIds) == 0 {
return fmt.Errorf("no users found in watchtower")
}
for _, stateUser := range r.UserIds {
ok := false
for _, gotUser := range userIDs {
if gotUser == stateUser {
fmt.Printf("[Debug] user found in WT: %s, %s", gotUser, stateUser)
ok = true
}
}
if !ok {
return fmt.Errorf("user in state not set in watchtower: %s", stateUser)
}
}
return nil
}
}
func testAccCheckRoleResourceGroupsSet(name string, groups []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("role resource not found: %s", name)
}
id := rs.Primary.ID
if id == "" {
return fmt.Errorf("role resource ID is not set")
}
groupIDs := []string{}
for _, groupResourceName := range groups {
gr, ok := s.RootModule().Resources[groupResourceName]
if !ok {
return fmt.Errorf("group resource not found: %s", groupResourceName)
}
groupID := gr.Primary.ID
if id == "" {
return fmt.Errorf("group resource ID not set")
}
groupIDs = append(groupIDs, groupID)
}
md := testProvider.Meta().(*metaData)
u := roles.Role{Id: id}
o := &scopes.Organization{
Client: md.client,
}
r, _, err := o.ReadRole(md.ctx, &u)
if err != nil {
return fmt.Errorf("Got an error when reading role %q: %v", id, err)
}
// for every user set as a principle on the role in the state, ensure
// each role in watchtower has the same setings
if len(r.GroupIds) == 0 {
return fmt.Errorf("no groups found in watchtower")
}
for _, stateGroup := range r.GroupIds {
ok := false
for _, gotGroup := range groupIDs {
if gotGroup == stateGroup {
fmt.Printf("[Debug] group found in WT: %s, %s", gotGroup, stateGroup)
ok = true
}
}
if !ok {
return fmt.Errorf("group in state not set in watchtower: %s", stateGroup)
}
}
return nil
}
}
func testAccCheckRoleResourceDestroy(t *testing.T) resource.TestCheckFunc {
return func(s *terraform.State) error {
md := testProvider.Meta().(*metaData)
@@ -146,6 +393,10 @@ func testAccCheckRoleResourceDestroy(t *testing.T) resource.TestCheckFunc {
for _, rs := range s.RootModule().Resources {
switch rs.Type {
case "watchtower_user":
continue
case "watchtower_group":
continue
case "watchtower_role":
id := rs.Primary.ID