1
0
mirror of https://github.com/rancher/norman.git synced 2025-06-05 21:43:04 +00:00
norman/clientbase/ops.go

324 lines
7.2 KiB
Go
Raw Normal View History

2017-11-11 04:44:02 +00:00
package clientbase
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"github.com/pkg/errors"
"github.com/rancher/norman/types"
)
func (a *APIOperations) setupRequest(req *http.Request) {
req.Header.Add("Authorization", a.Opts.getAuthHeader())
2017-11-11 04:44:02 +00:00
}
func (a *APIOperations) DoDelete(url string) error {
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
a.setupRequest(req)
resp, err := a.Client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
io.Copy(ioutil.Discard, resp.Body)
if resp.StatusCode >= 300 {
2017-11-21 20:46:30 +00:00
return newAPIError(resp, url)
2017-11-11 04:44:02 +00:00
}
return nil
}
func (a *APIOperations) DoGet(url string, opts *types.ListOpts, respObject interface{}) error {
if opts == nil {
opts = NewListOpts()
}
url, err := appendFilters(url, opts.Filters)
if err != nil {
return err
}
if debug {
fmt.Println("GET " + url)
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
a.setupRequest(req)
resp, err := a.Client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
2017-11-21 20:46:30 +00:00
return newAPIError(resp, url)
2017-11-11 04:44:02 +00:00
}
byteContent, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if debug {
fmt.Println("Response <= " + string(byteContent))
}
if err := json.Unmarshal(byteContent, respObject); err != nil {
return errors.Wrap(err, fmt.Sprintf("Failed to parse: %s", byteContent))
}
return nil
}
func (a *APIOperations) DoList(schemaType string, opts *types.ListOpts, respObject interface{}) error {
schema, ok := a.Types[schemaType]
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
if !contains(schema.CollectionMethods, "GET") {
return errors.New("Resource type [" + schemaType + "] is not listable")
}
2018-03-06 23:25:26 +00:00
return a.DoGet(a.Opts.URL+"/"+schemaType, opts, respObject)
2017-11-11 04:44:02 +00:00
}
2017-11-21 20:46:30 +00:00
func (a *APIOperations) DoNext(nextURL string, respObject interface{}) error {
return a.DoGet(nextURL, nil, respObject)
2017-11-11 04:44:02 +00:00
}
func (a *APIOperations) DoModify(method string, url string, createObj interface{}, respObject interface{}) error {
bodyContent, err := json.Marshal(createObj)
if err != nil {
return err
}
if debug {
fmt.Println(method + " " + url)
fmt.Println("Request => " + string(bodyContent))
}
req, err := http.NewRequest(method, url, bytes.NewBuffer(bodyContent))
if err != nil {
return err
}
a.setupRequest(req)
req.Header.Set("Content-Type", "application/json")
resp, err := a.Client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
2017-11-21 20:46:30 +00:00
return newAPIError(resp, url)
2017-11-11 04:44:02 +00:00
}
byteContent, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if len(byteContent) > 0 {
if debug {
fmt.Println("Response <= " + string(byteContent))
}
return json.Unmarshal(byteContent, respObject)
}
return nil
}
func (a *APIOperations) DoCreate(schemaType string, createObj interface{}, respObject interface{}) error {
if createObj == nil {
createObj = map[string]string{}
}
if respObject == nil {
respObject = &map[string]interface{}{}
}
schema, ok := a.Types[schemaType]
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
if !contains(schema.CollectionMethods, "POST") {
return errors.New("Resource type [" + schemaType + "] is not creatable")
}
// using collection link to post doesn't help the resources under project or cluster, because they need a projectId or clusterId in the path
// for example, v3/projects/foo/apps, v3/cluster/bar/namespaces
return a.DoModify("POST", a.Opts.URL+"/"+schemaType, createObj, respObject)
2017-11-11 04:44:02 +00:00
}
func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error {
if existing == nil {
return errors.New("Existing object is nil")
}
2017-11-21 20:46:30 +00:00
selfURL, ok := existing.Links[SELF]
2017-11-11 04:44:02 +00:00
if !ok {
2017-11-21 20:46:30 +00:00
return fmt.Errorf("failed to find self URL of [%v]", existing)
2017-11-11 04:44:02 +00:00
}
if updates == nil {
updates = map[string]string{}
}
if respObject == nil {
respObject = &map[string]interface{}{}
}
schema, ok := a.Types[schemaType]
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
if !contains(schema.ResourceMethods, "PUT") {
return errors.New("Resource type [" + schemaType + "] is not updatable")
}
2017-11-21 20:46:30 +00:00
return a.DoModify("PUT", selfURL, updates, respObject)
2017-11-11 04:44:02 +00:00
}
2017-11-11 05:33:03 +00:00
func (a *APIOperations) DoByID(schemaType string, id string, respObject interface{}) error {
2017-11-11 04:44:02 +00:00
schema, ok := a.Types[schemaType]
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
if !contains(schema.ResourceMethods, "GET") {
return errors.New("Resource type [" + schemaType + "] can not be looked up by ID")
}
2017-11-21 20:46:30 +00:00
collectionURL, ok := schema.Links[COLLECTION]
2017-11-11 04:44:02 +00:00
if !ok {
return errors.New("Failed to find collection URL for [" + schemaType + "]")
}
2017-11-21 20:46:30 +00:00
return a.DoGet(collectionURL+"/"+id, nil, respObject)
2017-11-11 04:44:02 +00:00
}
func (a *APIOperations) DoResourceDelete(schemaType string, existing *types.Resource) error {
schema, ok := a.Types[schemaType]
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
if !contains(schema.ResourceMethods, "DELETE") {
return errors.New("Resource type [" + schemaType + "] can not be deleted")
}
2017-11-21 20:46:30 +00:00
selfURL, ok := existing.Links[SELF]
2017-11-11 04:44:02 +00:00
if !ok {
2017-11-21 20:46:30 +00:00
return fmt.Errorf("failed to find self URL of [%v]", existing)
2017-11-11 04:44:02 +00:00
}
2017-11-21 20:46:30 +00:00
return a.DoDelete(selfURL)
2017-11-11 04:44:02 +00:00
}
func (a *APIOperations) DoAction(schemaType string, action string,
existing *types.Resource, inputObject, respObject interface{}) error {
if existing == nil {
return errors.New("Existing object is nil")
}
2017-11-21 20:46:30 +00:00
actionURL, ok := existing.Actions[action]
2017-11-11 04:44:02 +00:00
if !ok {
2017-11-21 20:46:30 +00:00
return fmt.Errorf("action [%v] not available on [%v]", action, existing)
2017-11-11 04:44:02 +00:00
}
return a.doAction(schemaType, action, actionURL, inputObject, respObject)
}
func (a *APIOperations) DoCollectionAction(schemaType string, action string,
existing *types.Collection, inputObject, respObject interface{}) error {
if existing == nil {
return errors.New("Existing object is nil")
}
actionURL, ok := existing.Actions[action]
if !ok {
return fmt.Errorf("action [%v] not available on [%v]", action, existing)
}
return a.doAction(schemaType, action, actionURL, inputObject, respObject)
}
func (a *APIOperations) doAction(
schemaType string,
action string,
actionURL string,
inputObject interface{},
respObject interface{},
) error {
_, ok := a.Types[schemaType]
2017-11-11 04:44:02 +00:00
if !ok {
return errors.New("Unknown schema type [" + schemaType + "]")
}
var input io.Reader
if inputObject != nil {
bodyContent, err := json.Marshal(inputObject)
if err != nil {
return err
}
if debug {
fmt.Println("Request => " + string(bodyContent))
}
input = bytes.NewBuffer(bodyContent)
}
2017-11-21 20:46:30 +00:00
req, err := http.NewRequest("POST", actionURL, input)
2017-11-11 04:44:02 +00:00
if err != nil {
return err
}
a.setupRequest(req)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Length", "0")
resp, err := a.Client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
2017-11-21 20:46:30 +00:00
return newAPIError(resp, actionURL)
2017-11-11 04:44:02 +00:00
}
byteContent, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if debug {
fmt.Println("Response <= " + string(byteContent))
}
return json.Unmarshal(byteContent, respObject)
}