go-ceph/cephfs/admin/response.go

143 lines
3.3 KiB
Go
Raw Normal View History

// +build !luminous,!mimic
package admin
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
var (
// ErrStatusNotEmpty may be returned if a call should not have a status
// string set but one is.
ErrStatusNotEmpty = errors.New("response status not empty")
// ErrBodyNotEmpty may be returned if a call should have an empty body but
// a body value is present.
ErrBodyNotEmpty = errors.New("response body not empty")
)
const (
deprecatedSuffix = "call is deprecated and will be removed in a future release"
missingPrefix = "No handler found"
einval = -22
)
type cephError interface {
ErrorCode() int
}
// NotImplementedError error values will be returned in the case that an API
// call is not available in the version of Ceph that is running in the target
// cluster.
type NotImplementedError struct {
response
}
// Error implements the error interface.
func (e NotImplementedError) Error() string {
return fmt.Sprintf("API call not implemented server-side: %s", e.status)
}
// response encapsulates the data returned by ceph and supports easy processing
// pipelines.
type response struct {
body []byte
status string
err error
}
// Ok returns true if the response contains no error.
func (r response) Ok() bool {
return r.err == nil
}
// Error implements the error interface.
func (r response) Error() string {
if r.status == "" {
return r.err.Error()
}
return fmt.Sprintf("%s: %q", r.err, r.status)
}
// Unwrap returns the error this response contains.
func (r response) Unwrap() error {
return r.err
}
// Status returns the status string value.
func (r response) Status() string {
return r.status
}
// End returns an error if the response contains an error or nil, indicating
// that response is no longer needed for processing.
func (r response) End() error {
if !r.Ok() {
if ce, ok := r.err.(cephError); ok {
if ce.ErrorCode() == einval && strings.HasPrefix(r.status, missingPrefix) {
return NotImplementedError{response: r}
}
}
return r
}
return nil
}
// noStatus asserts that the input response has no status value.
func (r response) noStatus() response {
if !r.Ok() {
return r
}
if r.status != "" {
return response{r.body, r.status, ErrStatusNotEmpty}
}
return r
}
// noBody asserts that the input response has no body value.
func (r response) noBody() response {
if !r.Ok() {
return r
}
if len(r.body) != 0 {
return response{r.body, r.status, ErrBodyNotEmpty}
}
return r
}
// noData asserts that the input response has no status or body values.
func (r response) noData() response {
return r.noStatus().noBody()
}
// filterDeprecated removes deprecation warnings from the response status.
// Use it when checking the response from calls that may be deprecated in ceph
// if you want those calls to continue working if the warning is present.
func (r response) filterDeprecated() response {
if !r.Ok() {
return r
}
if strings.HasSuffix(r.status, deprecatedSuffix) {
return response{r.body, "", r.err}
}
return r
}
// unmarshal data from the response body into v.
func (r response) unmarshal(v interface{}) response {
if !r.Ok() {
return r
}
if err := json.Unmarshal(r.body, v); err != nil {
return response{body: r.body, err: err}
}
return r
}
// newResponse returns a response.
func newResponse(b []byte, s string, e error) response {
return response{b, s, e}
}