-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
feat(lh-86969): add the ability to read users from an MSP tenant when…
… creating (#148) * feat(lh-86969): add the ability to read users from an MSP tenant when creating This commit reads the users in an MSP-managed tenant after creating, and before deleting or updating them. BREAKING CHANGE: The `role` field has been changed to a list field called `roles`. * chore(lh-86969): clean up example
- Loading branch information
1 parent
1022180
commit 978abd0
Showing
16 changed files
with
292 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,24 +14,60 @@ import ( | |
"github.com/jarcoal/httpmock" | ||
"github.com/stretchr/testify/assert" | ||
netHttp "net/http" | ||
"strconv" | ||
"testing" | ||
"time" | ||
) | ||
|
||
// Function to generate users | ||
func generateUsers(num int) []users.UserDetails { | ||
var createdUsers []users.UserDetails | ||
for i := 1; i <= num; i++ { | ||
uid := "uid" + strconv.Itoa(i) // Generate unique UID | ||
username := "user" + strconv.Itoa(i) // Generate usernames like user1, user2, etc. | ||
roles := []string{"ROLE_USER"} // Assign a default role; you can modify this as needed | ||
apiOnlyUser := i%2 == 0 // Example: alternate between true/false for ApiOnlyUser | ||
|
||
createdUsers = append(createdUsers, users.UserDetails{ | ||
Uid: uid, | ||
Username: username, | ||
Roles: roles, | ||
ApiOnlyUser: apiOnlyUser, | ||
}) | ||
} | ||
return createdUsers | ||
} | ||
|
||
// the create test also tests read! | ||
func TestCreate(t *testing.T) { | ||
httpmock.Activate() | ||
defer httpmock.DeactivateAndReset() | ||
|
||
t.Run("successfully create users in MSP-managed tenant", func(t *testing.T) { | ||
httpmock.Reset() | ||
var managedTenantUid = uuid.New().String() | ||
var createInp = users.MspCreateUsersInput{ | ||
var createInp = users.MspUsersInput{ | ||
TenantUid: managedTenantUid, | ||
Users: []users.UserDetails{ | ||
{Username: "[email protected]", Role: string(role.SuperAdmin), ApiOnlyUser: false}, | ||
{Username: "api-only-user", Role: string(role.ReadOnly), ApiOnlyUser: true}, | ||
{Username: "[email protected]", Roles: []string{string(role.SuperAdmin)}, ApiOnlyUser: false}, | ||
{Username: "api-only-user", Roles: []string{string(role.ReadOnly)}, ApiOnlyUser: true}, | ||
}, | ||
} | ||
|
||
var usersInCdoTenant = generateUsers(250) | ||
var usersWithIds []users.UserDetails | ||
for _, user := range createInp.Users { | ||
userWithId := users.UserDetails{ | ||
Uid: uuid.New().String(), | ||
Username: user.Username, | ||
Roles: user.Roles, | ||
ApiOnlyUser: user.ApiOnlyUser, | ||
} | ||
usersInCdoTenant = append(usersInCdoTenant, userWithId) | ||
usersWithIds = append(usersWithIds, userWithId) | ||
} | ||
firstUserPage := users.UserPage{Items: usersInCdoTenant[:200], Count: len(usersInCdoTenant), Limit: 200, Offset: 0} | ||
secondUserPage := users.UserPage{Items: usersInCdoTenant[200:], Count: len(usersInCdoTenant), Limit: 200, Offset: 200} | ||
var transactionUid = uuid.New().String() | ||
var inProgressTransaction = transaction.Type{ | ||
TransactionUid: transactionUid, | ||
|
@@ -66,22 +102,32 @@ func TestCreate(t *testing.T) { | |
inProgressTransaction.PollingUrl, | ||
httpmock.NewJsonResponderOrPanic(200, doneTransaction), | ||
) | ||
httpmock.RegisterResponder( | ||
netHttp.MethodGet, | ||
fmt.Sprintf("/api/rest/v1/msp/tenants/%s/users?limit=200&offset=0", managedTenantUid), | ||
httpmock.NewJsonResponderOrPanic(200, firstUserPage), | ||
) | ||
httpmock.RegisterResponder( | ||
netHttp.MethodGet, | ||
fmt.Sprintf("/api/rest/v1/msp/tenants/%s/users?limit=200&offset=200", managedTenantUid), | ||
httpmock.NewJsonResponderOrPanic(200, secondUserPage), | ||
) | ||
|
||
actual, err := users.Create(context.Background(), *http.MustNewWithConfig(baseUrl, "valid_token", 0, 0, time.Minute), createInp) | ||
|
||
assert.NotNil(t, actual, "Created users should have not been nil") | ||
assert.Nil(t, err, "Created users operation should have not been an error") | ||
assert.Equal(t, createInp.Users, *actual, "Created users operation should have been the same as the created tenant") | ||
assert.Equal(t, usersWithIds, *actual, "Created users operation should have been the same as the created tenant") | ||
}) | ||
|
||
t.Run("user creation transaction fails", func(t *testing.T) { | ||
httpmock.Reset() | ||
var managedTenantUid = uuid.New().String() | ||
var createInp = users.MspCreateUsersInput{ | ||
var createInp = users.MspUsersInput{ | ||
TenantUid: managedTenantUid, | ||
Users: []users.UserDetails{ | ||
{Username: "[email protected]", Role: string(role.SuperAdmin), ApiOnlyUser: false}, | ||
{Username: "api-only-user", Role: string(role.ReadOnly), ApiOnlyUser: true}, | ||
{Username: "[email protected]", Roles: []string{string(role.SuperAdmin)}, ApiOnlyUser: false}, | ||
{Username: "api-only-user", Roles: []string{string(role.ReadOnly)}, ApiOnlyUser: true}, | ||
}, | ||
} | ||
var transactionUid = uuid.New().String() | ||
|
@@ -132,11 +178,11 @@ func TestCreate(t *testing.T) { | |
t.Run("user creation API call fails", func(t *testing.T) { | ||
httpmock.Reset() | ||
var managedTenantUid = uuid.New().String() | ||
var createInp = users.MspCreateUsersInput{ | ||
var createInp = users.MspUsersInput{ | ||
TenantUid: managedTenantUid, | ||
Users: []users.UserDetails{ | ||
{Username: "[email protected]", Role: string(role.SuperAdmin), ApiOnlyUser: false}, | ||
{Username: "api-only-user", Role: string(role.ReadOnly), ApiOnlyUser: true}, | ||
{Username: "[email protected]", Roles: []string{string(role.SuperAdmin)}, ApiOnlyUser: false}, | ||
{Username: "api-only-user", Roles: []string{string(role.ReadOnly)}, ApiOnlyUser: true}, | ||
}, | ||
} | ||
var transactionUid = uuid.New().String() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package users | ||
|
||
import ( | ||
"context" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/url" | ||
mapset "github.com/deckarep/golang-set/v2" | ||
) | ||
|
||
func ReadCreatedUsersInTenant(ctx context.Context, client http.Client, readInput MspUsersInput) (*[]UserDetails, error) { | ||
client.Logger.Printf("Reading users in tenant %s\n", readInput.TenantUid) | ||
|
||
// create a map of the users that were created | ||
// find the list of deleted users by removing from the list every time a user is found in the response | ||
readUserDetailsMap := map[string]UserDetails{} | ||
for _, createdUser := range readInput.Users { | ||
readUserDetailsMap[createdUser.Username] = createdUser | ||
} | ||
|
||
limit := 200 | ||
offset := 0 | ||
count := 1 | ||
var readUrl string | ||
var userPage UserPage | ||
foundUsernames := mapset.NewSet[string]() | ||
|
||
for count > offset { | ||
client.Logger.Printf("Getting users from %d to %d\n", offset, offset+limit) | ||
readUrl = url.GetUsersInMspManagedTenant(client.BaseUrl(), readInput.TenantUid, limit, offset) | ||
req := client.NewGet(ctx, readUrl) | ||
if err := req.Send(&userPage); err != nil { | ||
return nil, err | ||
} | ||
for _, user := range userPage.Items { | ||
// add user to map if not present | ||
if _, exists := readUserDetailsMap[user.Username]; exists { | ||
client.Logger.Printf("Updating user information for %v\n", user) | ||
readUserDetailsMap[user.Username] = user | ||
foundUsernames.Add(user.Username) | ||
} | ||
} | ||
|
||
offset += limit | ||
count = userPage.Count | ||
client.Logger.Printf("Got %d users in tenant %s\n", count, readInput.TenantUid) | ||
} | ||
|
||
var readUserDetails []UserDetails | ||
for _, value := range readUserDetailsMap { | ||
// do not add in any users that were not found when we read from the API | ||
if foundUsernames.Contains(value.Username) { | ||
readUserDetails = append(readUserDetails, value) | ||
} | ||
} | ||
|
||
return &readUserDetails, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
data "cdo_msp_managed_tenant" "tenant" { | ||
name = "CDO_tenant-name" | ||
name = "CDO_test-tenant-name" | ||
} | ||
|
||
resource "cdo_msp_managed_tenant_users" "example" { | ||
tenant_uid = data.cdo_msp_managed_tenant.tenant.id | ||
users = [ | ||
{ | ||
username = "[email protected]", | ||
role = "ROLE_SUPER_ADMIN" | ||
roles = ["ROLE_SUPER_ADMIN"] | ||
api_only_user = false | ||
}, | ||
{ | ||
username = "[email protected]", | ||
role = "ROLE_ADMIN" | ||
roles = ["ROLE_ADMIN"] | ||
api_only_user = false | ||
} | ||
] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.