diff --git a/rgw/admin/errors.go b/rgw/admin/errors.go index ce9161a..7ce3c64 100644 --- a/rgw/admin/errors.go +++ b/rgw/admin/errors.go @@ -87,6 +87,7 @@ const ( var ( errMissingUserID = errors.New("missing user ID") + errMissingSubuserID = errors.New("missing subuser ID") errMissingUserAccessKey = errors.New("missing user access key") errMissingUserDisplayName = errors.New("missing user display name") errMissingUserCap = errors.New("missing user capabilities") diff --git a/rgw/admin/subuser.go b/rgw/admin/subuser.go new file mode 100644 index 0000000..32d5cef --- /dev/null +++ b/rgw/admin/subuser.go @@ -0,0 +1,107 @@ +//go:build ceph_preview +// +build ceph_preview + +package admin + +import ( + "context" + "fmt" + "net/http" +) + +// validateSubuserAcess - Return whether the given subuser access value is valid as input parameter +func (s SubuserSpec) validateSubuserAccess() bool { + a := s.Access + return a == "" || + a == SubuserAccessRead || + a == SubuserAccessWrite || + a == SubuserAccessReadWrite || + a == SubuserAccessFull +} + +func makeInvalidSubuserAccessLevelError(spec SubuserSpec) error { + return fmt.Errorf("invalid subuser access level %q", spec.Access) +} + +// The following are the subuser API functions. +// +// We need to explain the omission of ?subuser in the API path common +// to all three functions. +// +// According to the docs, this has to be included to select the +// subuser operation, but we already have subuser as a parameter with +// a value (and make sure it's not empty and thus included by +// validating the SubuserSpec). The presence of this parameter +// triggers the subuser operation. +// +// If we add the subuser with the empty value the API call fails as +// having an invalid signature (and it is semantically wrong as we +// then have *two* values for the subuser name, an empty one an the +// relevant one, the upstream code does not seem to handle that case +// gracefully). + +// CreateSubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#create-subuser +// PREVIEW +func (api *API) CreateSubuser(ctx context.Context, user User, subuser SubuserSpec) error { + if user.ID == "" { + return errMissingUserID + } + if subuser.Name == "" { + return errMissingSubuserID + } + if !subuser.validateSubuserAccess() { + return makeInvalidSubuserAccessLevelError(subuser) + } + // valid parameters not supported by go-ceph: access-key, gen-access-key + v := valueToURLParams(user, []string{"uid"}) + addToURLParams(&v, subuser, []string{"subuser", "access", "secret-key", "generate-secret", "key-type"}) + _, err := api.call(ctx, http.MethodPut, "/user", v) + if err != nil { + return err + } + + return nil +} + +// RemoveSubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#remove-subuser +// PREVIEW +func (api *API) RemoveSubuser(ctx context.Context, user User, subuser SubuserSpec) error { + if user.ID == "" { + return errMissingUserID + } + if subuser.Name == "" { + return errMissingSubuserID + } + + v := valueToURLParams(user, []string{"uid"}) + addToURLParams(&v, subuser, []string{"subuser", "purge-keys"}) + _, err := api.call(ctx, http.MethodDelete, "/user", v) + if err != nil { + return err + } + + return nil +} + +// ModifySubuser - https://docs.ceph.com/en/latest/radosgw/adminops/#modify-subuser +// PREVIEW +func (api *API) ModifySubuser(ctx context.Context, user User, subuser SubuserSpec) error { + if user.ID == "" { + return errMissingUserID + } + if subuser.Name == "" { + return errMissingSubuserID + } + if !subuser.validateSubuserAccess() { + return makeInvalidSubuserAccessLevelError(subuser) + } + + v := valueToURLParams(user, []string{"uid"}) + addToURLParams(&v, subuser, []string{"subuser", "access", "secret", "generate-secret", "key-type"}) + _, err := api.call(ctx, http.MethodPost, "/user", v) + if err != nil { + return err + } + + return nil +}