diff --git a/builder/digitalocean/api.go b/builder/digitalocean/api.go index e9525c0bf..86798633f 100644 --- a/builder/digitalocean/api.go +++ b/builder/digitalocean/api.go @@ -8,7 +8,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/mitchellh/mapstructure" "io/ioutil" "log" "net/http" @@ -16,9 +15,9 @@ import ( "strconv" "strings" "time" -) -const DIGITALOCEAN_API_URL = "https://api.digitalocean.com" + "github.com/mitchellh/mapstructure" +) type Image struct { Id uint @@ -55,23 +54,23 @@ type DigitalOceanClient struct { // The http client for communicating client *http.Client - // The base URL of the API - BaseURL string - // Credentials ClientID string APIKey string + + // The base URL of the API + APIURL string } // Creates a new client for communicating with DO -func (d DigitalOceanClient) New(client string, key string) *DigitalOceanClient { +func (d DigitalOceanClient) New(client string, key string, url string) *DigitalOceanClient { c := &DigitalOceanClient{ client: &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyFromEnvironment, }, }, - BaseURL: DIGITALOCEAN_API_URL, + APIURL: url, ClientID: client, APIKey: key, } @@ -229,7 +228,7 @@ func NewRequest(d DigitalOceanClient, path string, params url.Values) (map[strin params.Set("client_id", d.ClientID) params.Set("api_key", d.APIKey) - url := fmt.Sprintf("%s/%s?%s", DIGITALOCEAN_API_URL, path, params.Encode()) + url := fmt.Sprintf("%s/%s?%s", d.APIURL, path, params.Encode()) // Do some basic scrubbing so sensitive information doesn't appear in logs scrubbedUrl := strings.Replace(url, d.ClientID, "CLIENT_ID", -1) diff --git a/builder/digitalocean/builder.go b/builder/digitalocean/builder.go index 670f8ed77..282681636 100644 --- a/builder/digitalocean/builder.go +++ b/builder/digitalocean/builder.go @@ -6,13 +6,14 @@ package digitalocean import ( "errors" "fmt" + "log" + "os" + "time" + "github.com/mitchellh/multistep" "github.com/mitchellh/packer/common" "github.com/mitchellh/packer/common/uuid" "github.com/mitchellh/packer/packer" - "log" - "os" - "time" ) // see https://api.digitalocean.com/images/?client_id=[client_id]&api_key=[api_key] @@ -38,6 +39,7 @@ type config struct { ClientID string `mapstructure:"client_id"` APIKey string `mapstructure:"api_key"` + APIURL string `mapstructure:"api_url"` RegionID uint `mapstructure:"region_id"` SizeID uint `mapstructure:"size_id"` ImageID uint `mapstructure:"image_id"` @@ -94,6 +96,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.ClientID = os.Getenv("DIGITALOCEAN_CLIENT_ID") } + if b.config.APIURL == "" { + // Default to environment variable for api_url, if it exists + b.config.APIURL = os.Getenv("DIGITALOCEAN_API_URL") + } + if b.config.Region == "" { if b.config.RegionID != 0 { b.config.Region = fmt.Sprintf("%v", b.config.RegionID) @@ -153,6 +160,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { templates := map[string]*string{ "client_id": &b.config.ClientID, "api_key": &b.config.APIKey, + "api_url": &b.config.APIURL, "snapshot_name": &b.config.SnapshotName, "droplet_name": &b.config.DropletName, "ssh_username": &b.config.SSHUsername, @@ -175,6 +183,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs, errors.New("a client_id must be specified")) } + if b.config.APIURL == "" { + b.config.APIURL = "https://api.digitalocean.com" + } + if b.config.APIKey == "" { errs = packer.MultiErrorAppend( errs, errors.New("an api_key must be specified")) @@ -204,7 +216,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { // Initialize the DO API client - client := DigitalOceanClient{}.New(b.config.ClientID, b.config.APIKey) + client := DigitalOceanClient{}.New(b.config.ClientID, b.config.APIKey, b.config.APIURL) // Set up the state state := new(multistep.BasicStateBag) diff --git a/builder/digitalocean/step_create_droplet.go b/builder/digitalocean/step_create_droplet.go index 79a235413..a00cecac9 100644 --- a/builder/digitalocean/step_create_droplet.go +++ b/builder/digitalocean/step_create_droplet.go @@ -2,6 +2,7 @@ package digitalocean import ( "fmt" + "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" ) @@ -53,7 +54,7 @@ func (s *stepCreateDroplet) Cleanup(state multistep.StateBag) { err := client.DestroyDroplet(s.dropletId) if err != nil { curlstr := fmt.Sprintf("curl '%v/droplets/%v/destroy?client_id=%v&api_key=%v'", - DIGITALOCEAN_API_URL, s.dropletId, c.ClientID, c.APIKey) + c.APIURL, s.dropletId, c.ClientID, c.APIKey) ui.Error(fmt.Sprintf( "Error destroying droplet. Please destroy it manually: %v", curlstr)) diff --git a/builder/digitalocean/step_create_ssh_key.go b/builder/digitalocean/step_create_ssh_key.go index e686b1ec7..cecb4f8d5 100644 --- a/builder/digitalocean/step_create_ssh_key.go +++ b/builder/digitalocean/step_create_ssh_key.go @@ -1,16 +1,17 @@ package digitalocean import ( - "code.google.com/p/gosshold/ssh" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" + "log" + + "code.google.com/p/gosshold/ssh" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/common/uuid" "github.com/mitchellh/packer/packer" - "log" ) type stepCreateSSHKey struct { @@ -78,7 +79,7 @@ func (s *stepCreateSSHKey) Cleanup(state multistep.StateBag) { err := client.DestroyKey(s.keyId) curlstr := fmt.Sprintf("curl '%v/ssh_keys/%v/destroy?client_id=%v&api_key=%v'", - DIGITALOCEAN_API_URL, s.keyId, c.ClientID, c.APIKey) + c.APIURL, s.keyId, c.ClientID, c.APIKey) if err != nil { log.Printf("Error cleaning up ssh key: %v", err.Error())