As part of the unification it became clear where we did not support features that we had for the local backend. I opened issues and added comments.
120 lines
3.7 KiB
Go
120 lines
3.7 KiB
Go
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/pulumi/pulumi/pkg/apitype"
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
)
|
|
|
|
// pulumiCloudEndpoint returns the endpoint for the Pulumi Cloud Management Console API.
|
|
// e.g. "http://localhost:8080" or "https://api.moolumi.io".
|
|
func pulumiConsoleAPI() (string, error) {
|
|
envVar := os.Getenv("PULUMI_API")
|
|
if envVar == "" {
|
|
return "", fmt.Errorf("PULUMI_API env var not set")
|
|
}
|
|
return envVar, nil
|
|
}
|
|
|
|
// usePulumiCloudCommands returns whether or not to use the "Pulumi Cloud" version of CLI commands.
|
|
func usePulumiCloudCommands() bool {
|
|
_, err := pulumiConsoleAPI()
|
|
return err == nil
|
|
}
|
|
|
|
// cloudProjectIdentifier is the set of data needed to identify a Pulumi Cloud project. This the
|
|
// logical "home" of a stack on the Pulumi Cloud.
|
|
type cloudProjectIdentifier struct {
|
|
Owner string
|
|
Repository string
|
|
Project tokens.PackageName
|
|
}
|
|
|
|
// pulumiAPICall makes an HTTP request to the Pulumi API.
|
|
func pulumiAPICall(method string, path string, body []byte, accessToken string) (*http.Response, error) {
|
|
apiEndpoint, err := pulumiConsoleAPI()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting Pulumi API endpoint: %v", err)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/api%s", apiEndpoint, path)
|
|
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating new HTTP request: %v", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
// Apply credentials if provided.
|
|
if accessToken != "" {
|
|
req.Header.Set("Authorization", fmt.Sprintf("token %s", accessToken))
|
|
}
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("performing HTTP request: %v", err)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// pulumiRESTCall calls the pulumi REST API marshalling reqObj to JSON and using that as
|
|
// the request body (use nil for GETs), and if successful, marshalling the responseObj
|
|
// as JSON and storing it in respObj (use nil for NoContent). The error return type might
|
|
// be an instance of apitype.ErrorResponse, in which case will have the response code.
|
|
func pulumiRESTCall(method, path string, reqObj interface{}, respObj interface{}) error {
|
|
creds, err := getStoredCredentials()
|
|
if err != nil {
|
|
return fmt.Errorf("getting stored credentials: %v", err)
|
|
}
|
|
return pulumiRESTCallWithAccessToken(method, path, reqObj, respObj, creds.AccessToken)
|
|
}
|
|
|
|
// pulumiRESTCallWithAccessToken requires you pass in the auth token rather than reading it from the machine's config.
|
|
func pulumiRESTCallWithAccessToken(method, path string, reqObj interface{}, respObj interface{}, token string) error {
|
|
var reqBody []byte
|
|
var err error
|
|
if reqObj != nil {
|
|
reqBody, err = json.Marshal(reqObj)
|
|
if err != nil {
|
|
return fmt.Errorf("marshalling request object as JSON: %v", err)
|
|
}
|
|
}
|
|
|
|
resp, err := pulumiAPICall(method, path, reqBody, token)
|
|
if err != nil {
|
|
return fmt.Errorf("calling API: %v", err)
|
|
}
|
|
defer contract.IgnoreClose(resp.Body)
|
|
respBody, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("reading response from API: %v", err)
|
|
}
|
|
|
|
// 4xx and 5xx responses should be of type ErrorResponse. See if we can unmarshal as that
|
|
// type, and if not just return the raw response text.
|
|
if resp.StatusCode >= 400 && resp.StatusCode <= 599 {
|
|
var errResp apitype.ErrorResponse
|
|
if err = json.Unmarshal(respBody, &errResp); err != nil {
|
|
errResp.Code = resp.StatusCode
|
|
errResp.Message = string(respBody)
|
|
}
|
|
return &errResp
|
|
}
|
|
|
|
if respObj != nil {
|
|
if err = json.Unmarshal(respBody, respObj); err != nil {
|
|
return fmt.Errorf("unmarshalling response object: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|