215 lines
4.7 KiB
Go
215 lines
4.7 KiB
Go
|
package client
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"net/http/httputil"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"regexp"
|
||
|
"text/template"
|
||
|
)
|
||
|
|
||
|
const NON_VERBOSE = "NON_VERBOSE"
|
||
|
|
||
|
type HttpClient struct {
|
||
|
HTTPClient *http.Client
|
||
|
|
||
|
username string
|
||
|
password string
|
||
|
|
||
|
useHttps bool
|
||
|
|
||
|
apiUrl string
|
||
|
|
||
|
nonVerbose bool
|
||
|
|
||
|
templatePath string
|
||
|
}
|
||
|
|
||
|
func NewHttpsClient(username, password, apiUrl, templatePath string) *HttpClient {
|
||
|
return NewHttpClient(username, password, apiUrl, templatePath, true)
|
||
|
}
|
||
|
|
||
|
func NewHttpClient(username, password, apiUrl, templatePath string, useHttps bool) *HttpClient {
|
||
|
pwd, err := os.Getwd()
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
hClient := &HttpClient{
|
||
|
username: username,
|
||
|
password: password,
|
||
|
|
||
|
useHttps: useHttps,
|
||
|
|
||
|
apiUrl: apiUrl,
|
||
|
|
||
|
templatePath: filepath.Join(pwd, templatePath),
|
||
|
|
||
|
HTTPClient: http.DefaultClient,
|
||
|
|
||
|
nonVerbose: checkNonVerbose(),
|
||
|
}
|
||
|
|
||
|
return hClient
|
||
|
}
|
||
|
|
||
|
// Public methods
|
||
|
|
||
|
func (slc *HttpClient) DoRawHttpRequestWithObjectMask(path string, masks []string, requestType string, requestBody *bytes.Buffer) ([]byte, int, error) {
|
||
|
url := fmt.Sprintf("%s://%s:%s@%s/%s", slc.scheme(), slc.username, slc.password, slc.apiUrl, path)
|
||
|
|
||
|
url += "?objectMask="
|
||
|
for i := 0; i < len(masks); i++ {
|
||
|
url += masks[i]
|
||
|
if i != len(masks)-1 {
|
||
|
url += ";"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return slc.makeHttpRequest(url, requestType, requestBody)
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) DoRawHttpRequestWithObjectFilter(path string, filters string, requestType string, requestBody *bytes.Buffer) ([]byte, int, error) {
|
||
|
url := fmt.Sprintf("%s://%s:%s@%s/%s", slc.scheme(), slc.username, slc.password, slc.apiUrl, path)
|
||
|
url += "?objectFilter=" + filters
|
||
|
|
||
|
return slc.makeHttpRequest(url, requestType, requestBody)
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) DoRawHttpRequestWithObjectFilterAndObjectMask(path string, masks []string, filters string, requestType string, requestBody *bytes.Buffer) ([]byte, int, error) {
|
||
|
url := fmt.Sprintf("%s://%s:%s@%s/%s", slc.scheme(), slc.username, slc.password, slc.apiUrl, path)
|
||
|
|
||
|
url += "?objectFilter=" + filters
|
||
|
|
||
|
url += "&objectMask=filteredMask["
|
||
|
for i := 0; i < len(masks); i++ {
|
||
|
url += masks[i]
|
||
|
if i != len(masks)-1 {
|
||
|
url += ";"
|
||
|
}
|
||
|
}
|
||
|
url += "]"
|
||
|
|
||
|
return slc.makeHttpRequest(url, requestType, requestBody)
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) DoRawHttpRequest(path string, requestType string, requestBody *bytes.Buffer) ([]byte, int, error) {
|
||
|
url := fmt.Sprintf("%s://%s:%s@%s/%s", slc.scheme(), slc.username, slc.password, slc.apiUrl, path)
|
||
|
return slc.makeHttpRequest(url, requestType, requestBody)
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) GenerateRequestBody(templateData interface{}) (*bytes.Buffer, error) {
|
||
|
cwd, err := os.Getwd()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
bodyTemplate := template.Must(template.ParseFiles(filepath.Join(cwd, slc.templatePath)))
|
||
|
body := new(bytes.Buffer)
|
||
|
bodyTemplate.Execute(body, templateData)
|
||
|
|
||
|
return body, nil
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) HasErrors(body map[string]interface{}) error {
|
||
|
if errString, ok := body["error"]; !ok {
|
||
|
return nil
|
||
|
} else {
|
||
|
return errors.New(errString.(string))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) CheckForHttpResponseErrors(data []byte) error {
|
||
|
var decodedResponse map[string]interface{}
|
||
|
err := json.Unmarshal(data, &decodedResponse)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err := slc.HasErrors(decodedResponse); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Private methods
|
||
|
|
||
|
func (slc *HttpClient) scheme() string {
|
||
|
if !slc.useHttps {
|
||
|
return "http"
|
||
|
}
|
||
|
|
||
|
return "https"
|
||
|
}
|
||
|
|
||
|
func (slc *HttpClient) makeHttpRequest(url string, requestType string, requestBody *bytes.Buffer) ([]byte, int, error) {
|
||
|
req, err := http.NewRequest(requestType, url, requestBody)
|
||
|
if err != nil {
|
||
|
return nil, 0, err
|
||
|
}
|
||
|
|
||
|
bs, err := httputil.DumpRequest(req, true)
|
||
|
if err != nil {
|
||
|
return nil, 0, err
|
||
|
}
|
||
|
|
||
|
if !slc.nonVerbose {
|
||
|
fmt.Fprintf(os.Stderr, "\n---\n[softlayer-go] Request:\n%s\n", hideCredentials(string(bs)))
|
||
|
}
|
||
|
|
||
|
resp, err := slc.HTTPClient.Do(req)
|
||
|
if err != nil {
|
||
|
return nil, 520, err
|
||
|
}
|
||
|
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
bs, err = httputil.DumpResponse(resp, true)
|
||
|
if err != nil {
|
||
|
return nil, resp.StatusCode, err
|
||
|
}
|
||
|
|
||
|
if !slc.nonVerbose {
|
||
|
fmt.Fprintf(os.Stderr, "[softlayer-go] Response:\n%s\n", hideCredentials(string(bs)))
|
||
|
}
|
||
|
|
||
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
||
|
if err != nil {
|
||
|
return nil, resp.StatusCode, err
|
||
|
}
|
||
|
|
||
|
return responseBody, resp.StatusCode, nil
|
||
|
}
|
||
|
|
||
|
// Private functions
|
||
|
|
||
|
func hideCredentials(s string) string {
|
||
|
hiddenStr := "\"password\":\"******\""
|
||
|
r := regexp.MustCompile(`"password":"[^"]*"`)
|
||
|
|
||
|
return r.ReplaceAllString(s, hiddenStr)
|
||
|
}
|
||
|
|
||
|
func checkNonVerbose() bool {
|
||
|
slGoNonVerbose := os.Getenv(NON_VERBOSE)
|
||
|
switch slGoNonVerbose {
|
||
|
case "yes":
|
||
|
return true
|
||
|
case "YES":
|
||
|
return true
|
||
|
case "true":
|
||
|
return true
|
||
|
case "TRUE":
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|