Execute a raw request against a CS API. Will return the raw JSON data returned by the API and nil if no error occurred. If the API returns an error the result will be nil and the HTTP error code and CS error details. If a processing (code) error occurs the result will be nil and the generated error
(api string, post bool, params url.Values)
| 541 | // no error occurred. If the API returns an error the result will be nil and the HTTP error code and CS |
| 542 | // error details. If a processing (code) error occurs the result will be nil and the generated error |
| 543 | func (cs *CloudStackClient) newRawRequest(api string, post bool, params url.Values) (json.RawMessage, error) { |
| 544 | params.Set("apiKey", cs.apiKey) |
| 545 | params.Set("command", api) |
| 546 | params.Set("response", "json") |
| 547 | params.Set("signatureversion", "3") |
| 548 | params.Set("expires", time.Now().UTC().Add(15*time.Minute).Format(time.RFC3339)) |
| 549 | |
| 550 | // Generate signature for API call |
| 551 | // * Serialize parameters, URL encoding only values and sort them by key, done by EncodeValues |
| 552 | // * Convert the entire argument string to lowercase |
| 553 | // * Replace all instances of '+' to '%20' |
| 554 | // * Calculate HMAC SHA1 of argument string with CloudStack secret |
| 555 | // * URL encode the string and convert to base64 |
| 556 | s := EncodeValues(params) |
| 557 | s2 := strings.ToLower(s) |
| 558 | mac := hmac.New(sha1.New, []byte(cs.secret)) |
| 559 | mac.Write([]byte(s2)) |
| 560 | signature := base64.StdEncoding.EncodeToString(mac.Sum(nil)) |
| 561 | |
| 562 | var err error |
| 563 | var resp *http.Response |
| 564 | if !cs.HTTPGETOnly && post { |
| 565 | // The deployVirtualMachine API should be called using a POST call |
| 566 | // so we don't have to worry about the userdata size |
| 567 | |
| 568 | // Add the unescaped signature to the POST params |
| 569 | params.Set("signature", signature) |
| 570 | |
| 571 | // Make a POST call |
| 572 | resp, err = cs.client.PostForm(cs.baseURL, params) |
| 573 | } else { |
| 574 | // Create the final URL before we issue the request |
| 575 | url := cs.baseURL + "?" + s + "&signature=" + url.QueryEscape(signature) |
| 576 | |
| 577 | // Make a GET call |
| 578 | resp, err = cs.client.Get(url) |
| 579 | } |
| 580 | if err != nil { |
| 581 | return nil, err |
| 582 | } |
| 583 | defer resp.Body.Close() |
| 584 | |
| 585 | b, err := ioutil.ReadAll(resp.Body) |
| 586 | if err != nil { |
| 587 | return nil, err |
| 588 | } |
| 589 | |
| 590 | // Need to get the raw value to make the result play nice |
| 591 | b, err = getRawValue(b) |
| 592 | if err != nil { |
| 593 | return nil, err |
| 594 | } |
| 595 | |
| 596 | if resp.StatusCode != 200 { |
| 597 | var e CSError |
| 598 | if err := json.Unmarshal(b, &e); err != nil { |
| 599 | return nil, err |
| 600 | } |
no test coverage detected