Skip to content

Commit e1605ae

Browse files
authored
feat: add /roles endpoint (#11)
FEATURES: - added new endpoint `/roles` to display all available for assigning roles. IMPROVEMENTS: - removed hard-coded roles from codebase.
1 parent 1e47155 commit e1605ae

File tree

15 files changed

+288
-79
lines changed

15 files changed

+288
-79
lines changed

examples/federation-with-user/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ import (
1212
"github.com/selectel/iam-go/service/users"
1313
)
1414

15+
const (
16+
// Account/Project reader.
17+
Reader string = "reader"
18+
19+
// Account scope.
20+
AccountScope string = "account"
21+
)
22+
1523
var (
1624
// KeystoneToken
1725
token = "gAAAAA..."
@@ -88,7 +96,7 @@ func main() {
8896
ExternalID: userExternalID,
8997
ID: federation.ID,
9098
},
91-
Roles: []roles.Role{{Scope: roles.Account, RoleName: roles.Reader}},
99+
Roles: []roles.Role{{Scope: AccountScope, RoleName: Reader}},
92100
})
93101
if err != nil {
94102
fmt.Println(err)

examples/group-with-user/main.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ import (
1111
"github.com/selectel/iam-go/service/users"
1212
)
1313

14+
const (
15+
// Account/Project reader.
16+
Reader string = "reader"
17+
18+
// Account/Project member.
19+
Member string = "member"
20+
21+
// Account scope.
22+
AccountScope string = "account"
23+
)
24+
1425
var (
1526
// KeystoneToken
1627
token = "gAAAAA..."
@@ -52,7 +63,7 @@ func main() {
5263
AuthType: users.Local,
5364
Email: email,
5465
Federation: nil,
55-
Roles: []roles.Role{{Scope: roles.Account, RoleName: roles.Reader}},
66+
Roles: []roles.Role{{Scope: AccountScope, RoleName: Reader}},
5667
GroupIDs: []string{group.ID},
5768
})
5869
if err != nil {
@@ -61,11 +72,11 @@ func main() {
6172
}
6273
fmt.Printf("Step 2: Created User ID: %s Keystone ID: %s\n", user.ID, user.KeystoneID)
6374

64-
err = groupsAPI.AssignRoles(ctx, group.ID, []roles.Role{{Scope: roles.Account, RoleName: roles.Member}})
75+
err = groupsAPI.AssignRoles(ctx, group.ID, []roles.Role{{Scope: AccountScope, RoleName: Member}})
6576
if err != nil {
6677
log.Fatal(err)
6778
}
68-
fmt.Printf("Step 3: Assigned Role %s with scope %s to Group ID: %s\n", roles.Member, roles.Account, group.ID)
79+
fmt.Printf("Step 3: Assigned Role %s with scope %s to Group ID: %s\n", Member, AccountScope, group.ID)
6980

7081
updatedGroup, err := groupsAPI.Update(ctx, group.ID, groups.UpdateRequest{Name: updatedGroupName,
7182
Description: &updatedDescription})

examples/serviceuser-create-update-delete/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ import (
99
"github.com/selectel/iam-go/service/serviceusers"
1010
)
1111

12+
const (
13+
// Billing administrator.
14+
Billing string = "billing"
15+
16+
// Account scope.
17+
AccountScope string = "account"
18+
)
19+
1220
var (
1321
// KeystoneToken
1422
token = "gAAAAA..."
@@ -44,7 +52,7 @@ func main() {
4452
Enabled: true,
4553
Name: name,
4654
Password: password,
47-
Roles: []roles.Role{{Scope: roles.Account, RoleName: roles.Billing}},
55+
Roles: []roles.Role{{Scope: AccountScope, RoleName: Billing}},
4856
})
4957
if err != nil {
5058
fmt.Println(err)

examples/transfer-role/main.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ import (
99
"github.com/selectel/iam-go/service/users"
1010
)
1111

12+
const (
13+
// Billing administrator.
14+
Billing string = "billing"
15+
16+
// Account scope.
17+
AccountScope string = "account"
18+
)
19+
1220
func main() {
1321
// KeystoneToken
1422
token := "gAAAAA..."
@@ -46,7 +54,7 @@ func main() {
4654
var chosenUser *users.User
4755
for _, user := range allUsers.Users {
4856
for _, role := range user.Roles {
49-
if role.RoleName == roles.Billing && user.ID != "account_root" {
57+
if role.RoleName == Billing && user.ID != "account_root" {
5058
chosenUser = &user
5159
break
5260
}
@@ -57,18 +65,18 @@ func main() {
5765
}
5866

5967
if chosenUser == nil {
60-
fmt.Println("No billing role was found")
68+
fmt.Printf("No %s role was found\n", Billing)
6169
return
6270
}
6371

6472
// Step 1
65-
fmt.Printf("Step 1: User %s with the Billing role was found\n", chosenUser.ID)
73+
fmt.Printf("Step 1: User %s with the %s role was found\n", chosenUser.ID, Billing)
6674

6775
// Unassign the role.
6876
err = usersAPI.UnassignRoles(
6977
ctx,
7078
chosenUser.ID,
71-
[]roles.Role{{Scope: roles.Account, RoleName: roles.Billing}},
79+
[]roles.Role{{Scope: AccountScope, RoleName: Billing}},
7280
)
7381

7482
// Handle the error.
@@ -78,13 +86,13 @@ func main() {
7886
}
7987

8088
// Step 2
81-
fmt.Printf("Step 2: Unassigned the Billing role from User %s \n", chosenUser.ID)
89+
fmt.Printf("Step 2: Unassigned the %s role from User %s \n", Billing, chosenUser.ID)
8290

8391
// Assign the role.
8492
err = usersAPI.AssignRoles(
8593
ctx,
8694
userID,
87-
[]roles.Role{{Scope: roles.Account, RoleName: roles.Billing}},
95+
[]roles.Role{{Scope: AccountScope, RoleName: Billing}},
8896
)
8997

9098
// Handle the error.
@@ -93,5 +101,5 @@ func main() {
93101
}
94102

95103
// Step 3
96-
fmt.Printf("Step 3: Assigned the Billing role to User %s \n", userID)
104+
fmt.Printf("Step 3: Assigned the %s role to User %s \n", Billing, userID)
97105
}

examples/user-create-delete/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ import (
99
"github.com/selectel/iam-go/service/users"
1010
)
1111

12+
const (
13+
// Billing administrator.
14+
Billing string = "billing"
15+
16+
// Account scope.
17+
AccountScope string = "account"
18+
)
19+
1220
var (
1321
// KeystoneToken
1422
token = "gAAAAA..."
@@ -44,7 +52,7 @@ func main() {
4452
AuthType: users.Local,
4553
Email: email,
4654
Federation: nil,
47-
Roles: []roles.Role{{Scope: roles.Account, RoleName: roles.Billing}},
55+
Roles: []roles.Role{{Scope: AccountScope, RoleName: Billing}},
4856
})
4957
// Handle the error.
5058
if err != nil {

iam.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
baseclient "github.com/selectel/iam-go/internal/client"
1010
"github.com/selectel/iam-go/service/federations/saml"
1111
"github.com/selectel/iam-go/service/groups"
12+
"github.com/selectel/iam-go/service/roles"
1213
"github.com/selectel/iam-go/service/s3credentials"
1314
"github.com/selectel/iam-go/service/serviceusers"
1415
"github.com/selectel/iam-go/service/users"
@@ -56,6 +57,9 @@ type Client struct {
5657
// Groups instance is used to make requests against Selectel IAM API and manage Groups of users.
5758
Groups *groups.Service
5859

60+
// Roles instance is used to make requests against Selectel IAM API and list available roles.
61+
Roles *roles.Service
62+
5963
// S3Credentials instance is used to make requests against Selectel IAM API and manage S3 Credentials.
6064
S3Credentials *s3credentials.Service
6165

@@ -132,6 +136,7 @@ func New(opts ...Option) (*Client, error) {
132136
c.Users = users.New(c.baseClient)
133137
c.ServiceUsers = serviceusers.New(c.baseClient)
134138
c.Groups = groups.New(c.baseClient)
139+
c.Roles = roles.New(c.baseClient)
135140
c.S3Credentials = s3credentials.New(c.baseClient)
136141
c.SAMLFederations = saml.New(c.baseClient)
137142

iam_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
baseclient "github.com/selectel/iam-go/internal/client"
1313
"github.com/selectel/iam-go/service/federations/saml"
1414
"github.com/selectel/iam-go/service/groups"
15+
"github.com/selectel/iam-go/service/roles"
1516
"github.com/selectel/iam-go/service/s3credentials"
1617
"github.com/selectel/iam-go/service/serviceusers"
1718
"github.com/selectel/iam-go/service/users"
@@ -62,6 +63,7 @@ func TestNew(t *testing.T) {
6263
Users: users.New(baseClient),
6364
ServiceUsers: serviceusers.New(baseClient),
6465
Groups: groups.New(baseClient),
66+
Roles: roles.New(baseClient),
6567
S3Credentials: s3credentials.New(baseClient),
6668
SAMLFederations: saml.New(baseClient),
6769
}
@@ -105,6 +107,7 @@ func TestNew(t *testing.T) {
105107
Users: users.New(baseClient),
106108
ServiceUsers: serviceusers.New(baseClient),
107109
Groups: groups.New(baseClient),
110+
Roles: roles.New(baseClient),
108111
S3Credentials: s3credentials.New(baseClient),
109112
SAMLFederations: saml.New(baseClient),
110113
}
@@ -141,6 +144,7 @@ func TestNew(t *testing.T) {
141144
Users: users.New(baseClient),
142145
ServiceUsers: serviceusers.New(baseClient),
143146
Groups: groups.New(baseClient),
147+
Roles: roles.New(baseClient),
144148
S3Credentials: s3credentials.New(baseClient),
145149
SAMLFederations: saml.New(baseClient),
146150
}

service/groups/requests_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ import (
1717
)
1818

1919
const (
20+
// Account scope.
21+
AccountScope string = "account"
22+
23+
// Account/Project member.
24+
Member string = "member"
25+
2026
groupsURL = "iam/v1/groups"
2127
groupsIDURL = "iam/v1/groups/123"
2228
rolesURL = "iam/v1/groups/123/roles"
@@ -45,7 +51,7 @@ func TestList(t *testing.T) {
4551
Name: "test_name",
4652
Description: "test_description",
4753
Roles: []roles.Role{
48-
{Scope: roles.Account, RoleName: roles.Member},
54+
{Scope: AccountScope, RoleName: Member},
4955
},
5056
},
5157
}},
@@ -120,7 +126,7 @@ func TestGet(t *testing.T) {
120126
Name: "test_name",
121127
Description: "test_description",
122128
Roles: []roles.Role{
123-
{Scope: roles.Account, RoleName: roles.Member},
129+
{Scope: AccountScope, RoleName: Member},
124130
},
125131
},
126132
ServiceUsers: []ServiceUser{
@@ -432,7 +438,7 @@ func TestAssignRoles(t *testing.T) {
432438
args: args{
433439
groupID: "123",
434440
roles: []roles.Role{
435-
{Scope: roles.Account, RoleName: roles.Member},
441+
{Scope: AccountScope, RoleName: Member},
436442
},
437443
},
438444
prepare: func() {
@@ -449,7 +455,7 @@ func TestAssignRoles(t *testing.T) {
449455
args: args{
450456
groupID: "123",
451457
roles: []roles.Role{
452-
{Scope: roles.Account, RoleName: roles.Member},
458+
{Scope: AccountScope, RoleName: Member},
453459
},
454460
},
455461
prepare: func() {
@@ -502,7 +508,7 @@ func TestUnassignRoles(t *testing.T) {
502508
args: args{
503509
groupID: "123",
504510
roles: []roles.Role{
505-
{Scope: roles.Account, RoleName: roles.Member},
511+
{Scope: AccountScope, RoleName: Member},
506512
},
507513
},
508514
prepare: func() {
@@ -519,7 +525,7 @@ func TestUnassignRoles(t *testing.T) {
519525
args: args{
520526
groupID: "123",
521527
roles: []roles.Role{
522-
{Scope: roles.Account, RoleName: roles.Member},
528+
{Scope: AccountScope, RoleName: Member},
523529
},
524530
},
525531
prepare: func() {

service/roles/doc.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package roles provides a client for interacting with the Selectel Roles API.
2+
package roles

service/roles/requests.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package roles
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"net/url"
7+
8+
"github.com/selectel/iam-go/iamerrors"
9+
"github.com/selectel/iam-go/internal/client"
10+
)
11+
12+
const apiVersion = "iam/v1"
13+
14+
// Service is used to communicate with the Roles API.
15+
type Service struct {
16+
baseClient *client.BaseClient
17+
}
18+
19+
// New initialises Service with the given client.
20+
func New(baseClient *client.BaseClient) *Service {
21+
return &Service{
22+
baseClient: baseClient,
23+
}
24+
}
25+
26+
// List returns a list of roles available for assignment.
27+
func (s *Service) List(ctx context.Context) (*ListResponse, error) {
28+
path, err := url.JoinPath(apiVersion, "roles")
29+
if err != nil {
30+
return nil, iamerrors.Error{Err: iamerrors.ErrInternalAppError, Desc: err.Error()}
31+
}
32+
33+
response, err := s.baseClient.DoRequest(ctx, client.DoRequestInput{
34+
Body: nil,
35+
Method: http.MethodGet,
36+
Path: path,
37+
})
38+
if err != nil {
39+
//nolint:wrapcheck // DoRequest already wraps the error.
40+
return nil, err
41+
}
42+
43+
var roles ListResponse
44+
err = client.UnmarshalJSON(response, &roles)
45+
if err != nil {
46+
return nil, iamerrors.Error{Err: iamerrors.ErrInternalAppError, Desc: err.Error()}
47+
}
48+
return &roles, nil
49+
}

0 commit comments

Comments
 (0)