mirror of
https://github.com/ceph/go-ceph
synced 2025-03-05 10:57:56 +00:00
Following this discussion #492 This commit introduces a new package "rgw/admin" which helps you interact with the [RadosGW Admin Ops API](https://docs.ceph.com/en/latest/radosgw/adminops). Not all the API capabilities are covered by this commit, but this is a solid foundation for adding code on top. I'm expecting a few more iterations to make 100% complete. Also, the RadosGW Admin API is going to implement new functions soon (like bucket creation). So this library will live on and keep catching up. As many unit tests as possible have been added. A new integration test suite also runs. The "micro-osd.sh" now deploys a RGW and the integration suite tests on it. Thus the CI should cover it. Shout out to @QuentinPerez and @IrekFasikhov for their existing libraries. They were a very good inspiration to get started. Co-authored-by: Irek Fasikhov <malmyzh@gmail.com> Co-authored-by: Quentin Perez <qperez42@gmail.com> Signed-off-by: Sébastien Han <seb@redhat.com>
117 lines
3.7 KiB
Go
117 lines
3.7 KiB
Go
package admin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
// ErrUserExists - Attempt to create existing user
|
|
ErrUserExists errorReason = "UserAlreadyExists"
|
|
|
|
// ErrNoSuchUser - Attempt to create existing user
|
|
ErrNoSuchUser errorReason = "NoSuchUser"
|
|
|
|
// ErrInvalidAccessKey - Invalid access key specified
|
|
ErrInvalidAccessKey errorReason = "InvalidAccessKey"
|
|
|
|
// ErrInvalidSecretKey - Invalid secret key specified
|
|
ErrInvalidSecretKey errorReason = "InvalidSecretKey"
|
|
|
|
// ErrInvalidKeyType - Invalid key type specified
|
|
ErrInvalidKeyType errorReason = "InvalidKeyType"
|
|
|
|
// ErrKeyExists - Provided access key exists and belongs to another user
|
|
ErrKeyExists errorReason = "KeyExists"
|
|
|
|
// ErrEmailExists - Provided email address exists
|
|
ErrEmailExists errorReason = "EmailExists"
|
|
|
|
// ErrInvalidCapability - Attempt to remove an invalid admin capability
|
|
ErrInvalidCapability errorReason = "InvalidCapability"
|
|
|
|
// ErrSubuserExists - Specified subuser exists
|
|
ErrSubuserExists errorReason = "SubuserExists"
|
|
|
|
// ErrInvalidAccess - Invalid subuser access specified
|
|
ErrInvalidAccess errorReason = "InvalidAccess"
|
|
|
|
// ErrIndexRepairFailed - Bucket index repair failed
|
|
ErrIndexRepairFailed errorReason = "IndexRepairFailed"
|
|
|
|
// ErrBucketNotEmpty - Attempted to delete non-empty bucket
|
|
ErrBucketNotEmpty errorReason = "BucketNotEmpty"
|
|
|
|
// ErrObjectRemovalFailed - Unable to remove objects
|
|
ErrObjectRemovalFailed errorReason = "ObjectRemovalFailed"
|
|
|
|
// ErrBucketUnlinkFailed - Unable to unlink bucket from specified user
|
|
ErrBucketUnlinkFailed errorReason = "BucketUnlinkFailed"
|
|
|
|
// ErrBucketLinkFailed - Unable to link bucket to specified user
|
|
ErrBucketLinkFailed errorReason = "BucketLinkFailed"
|
|
|
|
// ErrNoSuchObject - Specified object does not exist
|
|
ErrNoSuchObject errorReason = "NoSuchObject"
|
|
|
|
// ErrIncompleteBody - Either bucket was not specified for a bucket policy request or bucket and object were not specified for an object policy request.
|
|
ErrIncompleteBody errorReason = "IncompleteBody"
|
|
|
|
// ErrNoSuchCap - User does not possess specified capability
|
|
ErrNoSuchCap errorReason = "NoSuchCap"
|
|
|
|
// ErrInternalError - Internal server error.
|
|
ErrInternalError errorReason = "InternalError"
|
|
|
|
// ErrAccessDenied - Access denied.
|
|
ErrAccessDenied errorReason = "AccessDenied"
|
|
|
|
// ErrNoSuchBucket - Bucket does not exist.
|
|
ErrNoSuchBucket errorReason = "NoSuchBucket"
|
|
|
|
// ErrNoSuchKey - No such access key.
|
|
ErrNoSuchKey errorReason = "NoSuchKey"
|
|
|
|
// ErrInvalidArgument - Invalid argument.
|
|
ErrInvalidArgument errorReason = "InvalidArgument"
|
|
|
|
// ErrUnknown - reports an unknown error
|
|
ErrUnknown errorReason = "Unknown"
|
|
|
|
unmarshalError = "failed to unmarshal radosgw http response"
|
|
)
|
|
|
|
var (
|
|
errMissingUserID = errors.New("missing user ID")
|
|
errMissingUserDisplayName = errors.New("missing user display name")
|
|
)
|
|
|
|
// errorReason is the reason of the error
|
|
type errorReason string
|
|
|
|
// statusError is the API response when an error occurs
|
|
type statusError struct {
|
|
Code string `json:"Code,omitempty"`
|
|
RequestID string `json:"RequestId,omitempty"`
|
|
HostID string `json:"HostId,omitempty"`
|
|
}
|
|
|
|
func handleStatusError(decodedResponse []byte) error {
|
|
statusError := statusError{}
|
|
err := json.Unmarshal(decodedResponse, &statusError)
|
|
if err != nil {
|
|
return fmt.Errorf("%s. %s. %w", unmarshalError, string(decodedResponse), err)
|
|
}
|
|
|
|
return statusError
|
|
}
|
|
|
|
func (e errorReason) Error() string { return string(e) }
|
|
|
|
// Is determines whether the error is known to be reported
|
|
func (e statusError) Is(target error) bool { return target == errorReason(e.Code) }
|
|
|
|
// Error returns non-empty string if there was an error.
|
|
func (e statusError) Error() string { return fmt.Sprintf("%s %s %s", e.Code, e.RequestID, e.HostID) }
|