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

chore(sdk): introduce User type separate from UserID type #152

Merged
merged 6 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion internal/controller/accesskey/accesskey.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext

cr.SetConditions(xpv1.Creating())

creds, err := c.cloudianService.CreateUserCredentials(ctx, cloudian.User{
creds, err := c.cloudianService.CreateUserCredentials(ctx, cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: cr.Spec.ForProvider.UserID,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
return managed.ExternalObservation{}, nil
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: groupID,
UserID: "*",
}
qos, err := c.cloudianService.GetQOS(ctx, user, cr.Spec.ForProvider.Region)
qos, err := c.cloudianService.GetQOS(ctx, guid, cr.Spec.ForProvider.Region)

if errors.Is(err, cloudian.ErrNotFound) {
return managed.ExternalObservation{ResourceExists: false}, nil
Expand Down Expand Up @@ -200,11 +200,11 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
return managed.ExternalCreation{}, err
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: "*",
}
if err := c.cloudianService.SetQOS(ctx, user, cr.Spec.ForProvider.Region, qos); err != nil {
if err := c.cloudianService.SetQOS(ctx, guid, cr.Spec.ForProvider.Region, qos); err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, errCreateQOS)
}

Expand All @@ -226,11 +226,11 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
return managed.ExternalUpdate{}, err
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: "*",
}
if err := c.cloudianService.SetQOS(ctx, user, cr.Spec.ForProvider.Region, qos); err != nil {
if err := c.cloudianService.SetQOS(ctx, guid, cr.Spec.ForProvider.Region, qos); err != nil {
return managed.ExternalUpdate{}, errors.Wrap(err, errCreateQOS)
}

Expand All @@ -249,11 +249,11 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) (managed.Ext

cr.SetConditions(xpv1.Deleting())

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: "*",
}
err := c.cloudianService.DeleteQOS(ctx, user, cr.Spec.ForProvider.Region)
err := c.cloudianService.DeleteQOS(ctx, guid, cr.Spec.ForProvider.Region)
if err != nil && !errors.Is(err, cloudian.ErrNotFound) {
return managed.ExternalDelete{}, errors.Wrap(err, errGetCreds)
}
Expand Down
17 changes: 10 additions & 7 deletions internal/controller/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
return managed.ExternalObservation{}, nil
}

_, err := c.cloudianService.GetUser(ctx, cloudian.User{
_, err := c.cloudianService.GetUser(ctx, cloudian.GroupUserID{
GroupID: group,
UserID: externalName})
if errors.Is(err, cloudian.ErrNotFound) {
Expand Down Expand Up @@ -193,16 +193,19 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
}

user := cloudian.User{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: meta.GetExternalName(mg),
GroupUserID: cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: meta.GetExternalName(mg),
},
UserType: cloudian.UserTypeUser,
}
if err := c.cloudianService.CreateUser(ctx, user); err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, errCreateUser)
}

// When Cloudian creates a user, a single access key is created inside it.
// Delete the access key, so that the user does not have any non-managed access keys.
creds, err := c.cloudianService.ListUserCredentials(ctx, user)
creds, err := c.cloudianService.ListUserCredentials(ctx, user.GroupUserID)
if err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, "failed to list access keys of user")
}
Expand Down Expand Up @@ -240,20 +243,20 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) (managed.Ext
return managed.ExternalDelete{}, errors.New(errNotUser)
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: meta.GetExternalName(mg),
}

creds, err := c.cloudianService.ListUserCredentials(ctx, user)
creds, err := c.cloudianService.ListUserCredentials(ctx, guid)
if err != nil {
return managed.ExternalDelete{}, err
}
if len(creds) > 0 {
return managed.ExternalDelete{}, errors.New("User has access keys and cannot be deleted")
}

if err := c.cloudianService.DeleteUser(ctx, user); err != nil {
if err := c.cloudianService.DeleteUser(ctx, guid); err != nil {
return managed.ExternalDelete{}, errors.Wrap(err, errDeleteUser)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
return managed.ExternalObservation{}, nil
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: groupID,
UserID: userID,
}
qos, err := c.cloudianService.GetQOS(ctx, user, cr.Spec.ForProvider.Region)
qos, err := c.cloudianService.GetQOS(ctx, guid, cr.Spec.ForProvider.Region)

if errors.Is(err, cloudian.ErrNotFound) {
return managed.ExternalObservation{ResourceExists: false}, nil
Expand Down Expand Up @@ -204,11 +204,11 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
return managed.ExternalCreation{}, err
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: cr.Spec.ForProvider.UserID,
}
if err := c.cloudianService.SetQOS(ctx, user, cr.Spec.ForProvider.Region, qos); err != nil {
if err := c.cloudianService.SetQOS(ctx, guid, cr.Spec.ForProvider.Region, qos); err != nil {
return managed.ExternalCreation{}, errors.Wrap(err, errCreateQOS)
}

Expand All @@ -230,11 +230,11 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
return managed.ExternalUpdate{}, err
}

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: cr.Spec.ForProvider.UserID,
}
if err := c.cloudianService.SetQOS(ctx, user, cr.Spec.ForProvider.Region, qos); err != nil {
if err := c.cloudianService.SetQOS(ctx, guid, cr.Spec.ForProvider.Region, qos); err != nil {
return managed.ExternalUpdate{}, errors.Wrap(err, errCreateQOS)
}

Expand All @@ -253,11 +253,11 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) (managed.Ext

cr.SetConditions(xpv1.Deleting())

user := cloudian.User{
guid := cloudian.GroupUserID{
GroupID: cr.Spec.ForProvider.GroupID,
UserID: cr.Spec.ForProvider.UserID,
}
err := c.cloudianService.DeleteQOS(ctx, user, cr.Spec.ForProvider.Region)
err := c.cloudianService.DeleteQOS(ctx, guid, cr.Spec.ForProvider.Region)
if err != nil && !errors.Is(err, cloudian.ErrNotFound) {
return managed.ExternalDelete{}, errors.Wrap(err, errGetCreds)
}
Expand Down
18 changes: 9 additions & 9 deletions internal/sdk/cloudian/qos.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (qos *QualityOfService) queryParams(params map[string]string) error {
// Default user-level QoS for the whole region (GroupID="*", UserID="ALL")
// Group-level QoS for a specific group (GroupID="<groupId>", UserID="*")
// Default group-level QoS for the whole region (GroupID="ALL", UserID="*")
func (client Client) SetQOS(ctx context.Context, user User, region string, qos QualityOfService) error {
func (client Client) SetQOS(ctx context.Context, guid GroupUserID, region string, qos QualityOfService) error {
for _, val := range qos.rawQueryParams() {
if val != nil && *val < -1 {
return fmt.Errorf("QoS limit values must be >= -1")
Expand All @@ -161,8 +161,8 @@ func (client Client) SetQOS(ctx context.Context, user User, region string, qos Q
}

resp, err := client.newRequest(ctx).
SetQueryParam("userId", user.UserID).
SetQueryParam("groupId", user.GroupID).
SetQueryParam("userId", guid.UserID).
SetQueryParam("groupId", guid.GroupID).
SetQueryParams(params).
Post("/qos/limits")
if err != nil {
Expand All @@ -179,15 +179,15 @@ func (client Client) SetQOS(ctx context.Context, user User, region string, qos Q

// SetQOS gets QualityOfService limits for a Group or User, depending on the value of GroupID and UserID.
// See SetQOS for details.
func (client Client) GetQOS(ctx context.Context, user User, region string) (*QualityOfService, error) {
func (client Client) GetQOS(ctx context.Context, guid GroupUserID, region string) (*QualityOfService, error) {
params := make(map[string]string)
if region != DefaultRegion {
params["region"] = region
}

resp, err := client.newRequest(ctx).
SetQueryParam("userId", user.UserID).
SetQueryParam("groupId", user.GroupID).
SetQueryParam("userId", guid.UserID).
SetQueryParam("groupId", guid.GroupID).
SetQueryParams(params).
Get("/qos/limits")
if err != nil {
Expand Down Expand Up @@ -218,15 +218,15 @@ func (client Client) GetQOS(ctx context.Context, user User, region string) (*Qua

// DeleteQOS deletes QualityOfService limits for a Group or User, depending on the value of GroupID and UserID.
// See SetQOS for details.
func (client Client) DeleteQOS(ctx context.Context, user User, region string) error {
func (client Client) DeleteQOS(ctx context.Context, guid GroupUserID, region string) error {
params := make(map[string]string)
if region != DefaultRegion {
params["region"] = region
}

resp, err := client.newRequest(ctx).
SetQueryParam("userId", user.UserID).
SetQueryParam("groupId", user.GroupID).
SetQueryParam("userId", guid.UserID).
SetQueryParam("groupId", guid.GroupID).
SetQueryParams(params).
Delete("/qos/limits")
if err != nil {
Expand Down
57 changes: 29 additions & 28 deletions internal/sdk/cloudian/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,22 @@ func fromInternal(g groupInternal) Group {
}
}

type User struct {
UserID string `json:"userId"`
GroupID string `json:"groupId"`
}
type UserType string

const (
UserTypeSystemAdmin UserType = "SystemAdmin"
UserTypeGroupAdmin UserType = "GroupAdmin"
UserTypeUser UserType = "User"
)

type userInternal struct {
UserID string `json:"userId"`
GroupID string `json:"groupId"`
UserType string `json:"userType"`
type GroupUserID struct {
GroupID string `json:"groupId"`
UserID string `json:"userId"`
}

func toInternalUser(u User) userInternal {
return userInternal{
UserID: u.UserID,
GroupID: u.GroupID,
UserType: "User",
}
type User struct {
GroupUserID `json:",inline"`
UserType UserType `json:"userType"`
}

// SecurityInfo is the Cloudian API's term for secure credentials
Expand Down Expand Up @@ -157,7 +156,7 @@ func (client Client) ListUsers(ctx context.Context, groupID string, userID *stri
// Paginated API endpoint where limit+1 elements indicates more pages
if len(users) > ListLimit {
// Fetch remaining users starting from the user after the limit
moreUsers, err := client.ListUsers(ctx, groupID, &users[ListLimit].UserID)
moreUsers, err := client.ListUsers(ctx, groupID, &users[ListLimit].GroupUserID.UserID)
if err != nil {
return nil, err
}
Expand All @@ -169,11 +168,11 @@ func (client Client) ListUsers(ctx context.Context, groupID string, userID *stri
}

// Delete a single user. Errors if the user does not exist.
func (client Client) DeleteUser(ctx context.Context, user User) error {
func (client Client) DeleteUser(ctx context.Context, guid GroupUserID) error {
resp, err := client.newRequest(ctx).
SetQueryParams(map[string]string{
"groupId": user.GroupID,
"userId": user.UserID,
"groupId": guid.GroupID,
"userId": guid.UserID,
}).
Delete("/user")
if err != nil {
Expand All @@ -192,7 +191,7 @@ func (client Client) DeleteUser(ctx context.Context, user User) error {
// Create a single user of type `User` into a groupId
func (client Client) CreateUser(ctx context.Context, user User) error {
resp, err := client.newRequest(ctx).
SetBody(toInternalUser(user)).
SetBody(user).
Put("/user")
if err != nil {
return err
Expand All @@ -208,13 +207,15 @@ func (client Client) CreateUser(ctx context.Context, user User) error {

// GetUser gets a user. Returns an error even in the case of a user not found.
// This error can then be checked against ErrNotFound: errors.Is(err, ErrNotFound)
func (client Client) GetUser(ctx context.Context, user User) (*User, error) {
// FIXME: Introduce UserId struct and enrich User
func (client Client) GetUser(ctx context.Context, guid GroupUserID) (*User, error) {
var user User

resp, err := client.newRequest(ctx).
SetQueryParams(map[string]string{
"groupId": user.GroupID,
"userId": user.UserID,
"groupId": guid.GroupID,
"userId": guid.UserID,
}).
SetResult(&user).
Get("/user")
if err != nil {
return nil, err
Expand All @@ -232,12 +233,12 @@ func (client Client) GetUser(ctx context.Context, user User) (*User, error) {
}

// CreateUserCredentials creates a new set of credentials for a user.
func (client Client) CreateUserCredentials(ctx context.Context, user User) (*SecurityInfo, error) {
func (client Client) CreateUserCredentials(ctx context.Context, guid GroupUserID) (*SecurityInfo, error) {
var securityInfo SecurityInfo

resp, err := client.newRequest(ctx).
SetResult(&securityInfo).
SetQueryParams(map[string]string{"groupId": user.GroupID, "userId": user.UserID}).
SetQueryParams(map[string]string{"groupId": guid.GroupID, "userId": guid.UserID}).
Put("/user/credentials")
if err != nil {
return nil, err
Expand Down Expand Up @@ -275,11 +276,11 @@ func (client Client) GetUserCredentials(ctx context.Context, accessKey string) (
}

// ListUserCredentials fetches all the credentials of a user.
func (client Client) ListUserCredentials(ctx context.Context, user User) ([]SecurityInfo, error) {
func (client Client) ListUserCredentials(ctx context.Context, guid GroupUserID) ([]SecurityInfo, error) {
var securityInfo []SecurityInfo

resp, err := client.newRequest(ctx).
SetQueryParams(map[string]string{"groupId": user.GroupID, "userId": user.UserID}).
SetQueryParams(map[string]string{"groupId": guid.GroupID, "userId": guid.UserID}).
SetResult(&securityInfo).
Get("/user/credentials/list")
if err != nil {
Expand Down Expand Up @@ -322,7 +323,7 @@ func (client Client) DeleteGroupRecursive(ctx context.Context, groupID string) e
}

for _, user := range users {
if err := client.DeleteUser(ctx, user); err != nil {
if err := client.DeleteUser(ctx, user.GroupUserID); err != nil {
return fmt.Errorf("error deleting user: %w", err)
}
}
Expand Down
Loading
Loading