mirror of
https://github.com/ceph/go-ceph
synced 2024-12-18 12:25:22 +00:00
1de6083536
The following changes have been done:
* Up until now everything in the argument objects was serialized to
the API calls. This was updated to restrict the serialization to
the API call parameters that are parsed in the Ceph RGW source code.
Parameters not yet supported by us are documented as comments.
Note, that a superset of the documented parameters is supported.
Documentation for the API:
<https://docs.ceph.com/en/pacific/radosgw/adminops/>
Link to the used source tree:
<193895ffba/src/rgw
>
The argument parsing happens in the rgw_rest_*.cc files.
* The serialization code (valueToURLParams) has been updated to
be more in line with other serialization methods:
- A tag "-" causes the field to be ignored
- Only the first item in a list of tag items is interpreted as
name.
- The handling of pointer and direct data types has been
harmonized (the same rules for the names and value apply now).
* There is still room for improvement to make things more consistent:
A pointer to a non-elementary data type will emit unexpected
request parameters.
* Presence of required parameters is not validated by the library,
this is left to the API.
Signed-off-by: Sebastian Riese <sebastian.riese@cloudandheat.com>
106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
package admin
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
queryAdminPath = "/admin"
|
|
)
|
|
|
|
func buildQueryPath(endpoint, path, args string) string {
|
|
// Sometimes the API requires single URL key with no values
|
|
// For instance, the Quota code uses the admin API path to "/user?quota"
|
|
// This is done this way since url.Values does not support adding keys without values.
|
|
//
|
|
// So Quota code passes the begining of the query (indicated with a marker "?") in its path already, so we need to escape it
|
|
// and add a separator key instead
|
|
// So we can get something like "/admin/user?quota&" instead of passing two beginning query markers ("?")
|
|
if strings.Contains(path, "?") {
|
|
return fmt.Sprintf("%s%s%s&%s", endpoint, queryAdminPath, path, args)
|
|
}
|
|
|
|
return fmt.Sprintf("%s%s%s?%s", endpoint, queryAdminPath, path, args)
|
|
}
|
|
|
|
// valueToURLParams encodes structs into URL query parameters.
|
|
func valueToURLParams(i interface{}, accpetableFields []string) url.Values {
|
|
values := url.Values{}
|
|
|
|
// Always return json
|
|
values.Add("format", "json")
|
|
|
|
getReflect(i, accpetableFields, &values)
|
|
return values
|
|
}
|
|
|
|
func addToURLParams(v *url.Values, i interface{}, acceptableFields []string) {
|
|
getReflect(i, acceptableFields, v)
|
|
}
|
|
|
|
// NOTE: we use linear search here, as none of the API endpoints
|
|
// supports more than 10 parameters, in this case asymptotics don't
|
|
// matter and we are likely faster this way (even when compared to a
|
|
// map).
|
|
func contains(tagList []string, tag string) bool {
|
|
for _, tag2 := range tagList {
|
|
if tag == tag2 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func getReflect(i interface{}, acceptableFields []string, values *url.Values) {
|
|
t := reflect.TypeOf(i)
|
|
v := reflect.ValueOf(i)
|
|
|
|
for b := 0; b < v.NumField(); b++ {
|
|
v2 := v.Field(b)
|
|
tag := t.Field(b).Tag.Get("url")
|
|
if tag == "-" {
|
|
continue
|
|
}
|
|
tagList := strings.Split(tag, ",")
|
|
name := tagList[0]
|
|
if len(name) == 0 {
|
|
name = t.Field(b).Name
|
|
}
|
|
|
|
if v2.Kind() == reflect.Struct {
|
|
getReflect(v2.Interface(), acceptableFields, values)
|
|
continue
|
|
}
|
|
|
|
if v2.Kind() == reflect.Slice {
|
|
for i := 0; i < v2.Len(); i++ {
|
|
item := v2.Index(i)
|
|
getReflect(item.Interface(), acceptableFields, values)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if v2.Kind() == reflect.String ||
|
|
v2.Kind() == reflect.Bool ||
|
|
v2.Kind() == reflect.Int {
|
|
|
|
_v2 := fmt.Sprint(v2)
|
|
if len(_v2) > 0 && contains(acceptableFields, name) {
|
|
values.Add(name, _v2)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if v2.Kind() == reflect.Ptr && v2.IsValid() && !v2.IsNil() {
|
|
_v2 := fmt.Sprint(v2.Elem())
|
|
if len(_v2) > 0 && contains(acceptableFields, name) {
|
|
values.Add(name, _v2)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|