123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- // Copyright (c) 2016 VMware, Inc. All Rights Reserved.
- //
- // This product is licensed to you under the Apache License, Version 2.0 (the "License").
- // You may not use this product except in compliance with the License.
- //
- // This product may include a number of subcomponents with separate copyright notices and
- // license terms. Your use of these subcomponents is subject to the terms and conditions
- // of the subcomponent's license, as noted in the LICENSE file.
- package photon
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "reflect"
- )
- // Reads an error out of the HTTP response, or does nothing if
- // no error occured.
- func getError(res *http.Response) (*http.Response, error) {
- // Do nothing if the response is a successful 2xx
- if res.StatusCode/100 == 2 {
- return res, nil
- }
- var apiError ApiError
- // ReadAll is usually a bad practice, but here we need to read the response all
- // at once because we may attempt to use the data twice. It's preferable to use
- // methods that take io.Reader, e.g. json.NewDecoder
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(body, &apiError)
- if err != nil {
- // If deserializing into ApiError fails, return a generic HttpError instead
- return nil, HttpError{res.StatusCode, string(body[:])}
- }
- apiError.HttpStatusCode = res.StatusCode
- return nil, apiError
- }
- // Reads a task object out of the HTTP response. Takes an error argument
- // so that GetTask can easily wrap GetError. This function will do nothing
- // if e is not nil.
- // e.g. res, err := getTask(getError(someApi.Get()))
- func getTask(res *http.Response, e error) (*Task, error) {
- if e != nil {
- return nil, e
- }
- var task Task
- err := json.NewDecoder(res.Body).Decode(&task)
- if err != nil {
- return nil, err
- }
- if task.State == "ERROR" {
- // Critical: return task as well, so that it can be examined
- // for error details.
- return &task, TaskError{task.ID, getFailedStep(&task)}
- }
- return &task, nil
- }
- // Converts an options struct into a query string.
- // E.g. type Foo struct {A int; B int} might return "?a=5&b=10".
- // Will return an empty string if no options are set.
- func getQueryString(options interface{}) string {
- buffer := bytes.Buffer{}
- buffer.WriteString("?")
- strct := reflect.ValueOf(options).Elem()
- typ := strct.Type()
- for i := 0; i < strct.NumField(); i++ {
- field := strct.Field(i)
- value := fmt.Sprint(field.Interface())
- if value != "" {
- buffer.WriteString(typ.Field(i).Tag.Get("urlParam") + "=" + url.QueryEscape(value))
- if i < strct.NumField()-1 {
- buffer.WriteString("&")
- }
- }
- }
- uri := buffer.String()
- if uri == "?" {
- return ""
- }
- return uri
- }
- // Sets security groups for a given entity (deployment/tenant/project)
- func setSecurityGroups(client *Client, entityUrl string, securityGroups *SecurityGroupsSpec) (task *Task, err error) {
- body, err := json.Marshal(securityGroups)
- if err != nil {
- return
- }
- url := entityUrl + "/set_security_groups"
- res, err := client.restClient.Post(
- url,
- "application/json",
- bytes.NewReader(body),
- client.options.TokenOptions)
- if err != nil {
- return
- }
- defer res.Body.Close()
- task, err = getTask(getError(res))
- return
- }
|