package clientbase import ( "bytes" "encoding/json" "fmt" "io" "io/ioutil" "net/http" "regexp" "github.com/pkg/errors" "github.com/rancher/norman/types" ) func (a *APIOperations) setupRequest(req *http.Request) { req.SetBasicAuth(a.Opts.AccessKey, a.Opts.SecretKey) } 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 { return newApiError(resp, url) } 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 { return newApiError(resp, url) } 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") } collectionUrl, ok := schema.Links[COLLECTION] if !ok { return errors.New("Failed to find collection URL for [" + schemaType + "]") } return a.DoGet(collectionUrl, opts, respObject) } func (a *APIOperations) DoNext(nextUrl string, respObject interface{}) error { return a.DoGet(nextUrl, nil, respObject) } 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 { return newApiError(resp, url) } 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") } var collectionUrl string collectionUrl, ok = schema.Links[COLLECTION] if !ok { // return errors.New("Failed to find collection URL for [" + schemaType + "]") // This is a hack to address https://github.com/rancher/cattle/issues/254 re := regexp.MustCompile("schemas.*") collectionUrl = re.ReplaceAllString(schema.Links[SELF], schema.PluralName) } return a.DoModify("POST", collectionUrl, createObj, respObject) } func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error { if existing == nil { return errors.New("Existing object is nil") } selfUrl, ok := existing.Links[SELF] if !ok { return errors.New(fmt.Sprintf("Failed to find self URL of [%v]", existing)) } 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") } return a.DoModify("PUT", selfUrl, updates, respObject) } func (a *APIOperations) DoByID(schemaType string, id string, respObject interface{}) error { 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") } collectionUrl, ok := schema.Links[COLLECTION] if !ok { return errors.New("Failed to find collection URL for [" + schemaType + "]") } return a.DoGet(collectionUrl+"/"+id, nil, respObject) } 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") } selfUrl, ok := existing.Links[SELF] if !ok { return errors.New(fmt.Sprintf("Failed to find self URL of [%v]", existing)) } return a.DoDelete(selfUrl) } 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") } actionUrl, ok := existing.Actions[action] if !ok { return errors.New(fmt.Sprintf("Action [%v] not available on [%v]", action, existing)) } _, ok = a.Types[schemaType] 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) } req, err := http.NewRequest("POST", actionUrl, input) 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 { return newApiError(resp, actionUrl) } byteContent, err := ioutil.ReadAll(resp.Body) if err != nil { return err } if debug { fmt.Println("Response <= " + string(byteContent)) } return json.Unmarshal(byteContent, respObject) }