builder/digitalocean: No need for destroy steps, builder works!
This commit is contained in:
parent
a774e2b444
commit
8ba8932552
|
@ -9,7 +9,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DIGITALOCEAN_API_URL = "https://api.digitalocean.com"
|
const DIGITALOCEAN_API_URL = "https://api.digitalocean.com"
|
||||||
|
@ -39,7 +41,10 @@ func (d DigitalOceanClient) New(client string, key string) *DigitalOceanClient {
|
||||||
|
|
||||||
// Creates an SSH Key and returns it's id
|
// Creates an SSH Key and returns it's id
|
||||||
func (d DigitalOceanClient) CreateKey(name string, pub string) (uint, error) {
|
func (d DigitalOceanClient) CreateKey(name string, pub string) (uint, error) {
|
||||||
params := fmt.Sprintf("?name=%s&ssh_pub_key=%s", name, pub)
|
// Escape the public key
|
||||||
|
pub = url.QueryEscape(pub)
|
||||||
|
|
||||||
|
params := fmt.Sprintf("name=%v&ssh_pub_key=%v", name, pub)
|
||||||
|
|
||||||
body, err := NewRequest(d, "ssh_keys/new", params)
|
body, err := NewRequest(d, "ssh_keys/new", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -54,7 +59,7 @@ func (d DigitalOceanClient) CreateKey(name string, pub string) (uint, error) {
|
||||||
|
|
||||||
// Destroys an SSH key
|
// Destroys an SSH key
|
||||||
func (d DigitalOceanClient) DestroyKey(id uint) error {
|
func (d DigitalOceanClient) DestroyKey(id uint) error {
|
||||||
path := fmt.Sprintf("ssh_keys/%s/destroy", id)
|
path := fmt.Sprintf("ssh_keys/%v/destroy", id)
|
||||||
_, err := NewRequest(d, path, "")
|
_, err := NewRequest(d, path, "")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -62,8 +67,8 @@ func (d DigitalOceanClient) DestroyKey(id uint) error {
|
||||||
// Creates a droplet and returns it's id
|
// Creates a droplet and returns it's id
|
||||||
func (d DigitalOceanClient) CreateDroplet(name string, size uint, image uint, region uint, keyId uint) (uint, error) {
|
func (d DigitalOceanClient) CreateDroplet(name string, size uint, image uint, region uint, keyId uint) (uint, error) {
|
||||||
params := fmt.Sprintf(
|
params := fmt.Sprintf(
|
||||||
"name=%s&size_id=%s&image_id=%s&size_id=%s&image_id=%s®ion_id=%s&ssh_key_ids=%s",
|
"name=%v&image_id=%v&size_id=%v®ion_id=%v&ssh_key_ids=%v",
|
||||||
name, size, image, size, region, keyId)
|
name, image, size, region, keyId)
|
||||||
|
|
||||||
body, err := NewRequest(d, "droplets/new", params)
|
body, err := NewRequest(d, "droplets/new", params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -78,14 +83,14 @@ func (d DigitalOceanClient) CreateDroplet(name string, size uint, image uint, re
|
||||||
|
|
||||||
// Destroys a droplet
|
// Destroys a droplet
|
||||||
func (d DigitalOceanClient) DestroyDroplet(id uint) error {
|
func (d DigitalOceanClient) DestroyDroplet(id uint) error {
|
||||||
path := fmt.Sprintf("droplets/%s/destroy", id)
|
path := fmt.Sprintf("droplets/%v/destroy", id)
|
||||||
_, err := NewRequest(d, path, "")
|
_, err := NewRequest(d, path, "")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Powers off a droplet
|
// Powers off a droplet
|
||||||
func (d DigitalOceanClient) PowerOffDroplet(id uint) error {
|
func (d DigitalOceanClient) PowerOffDroplet(id uint) error {
|
||||||
path := fmt.Sprintf("droplets/%s/power_off", id)
|
path := fmt.Sprintf("droplets/%v/power_off", id)
|
||||||
|
|
||||||
_, err := NewRequest(d, path, "")
|
_, err := NewRequest(d, path, "")
|
||||||
|
|
||||||
|
@ -94,8 +99,8 @@ func (d DigitalOceanClient) PowerOffDroplet(id uint) error {
|
||||||
|
|
||||||
// Creates a snaphot of a droplet by it's ID
|
// Creates a snaphot of a droplet by it's ID
|
||||||
func (d DigitalOceanClient) CreateSnapshot(id uint, name string) error {
|
func (d DigitalOceanClient) CreateSnapshot(id uint, name string) error {
|
||||||
path := fmt.Sprintf("droplets/%s/snapshot", id)
|
path := fmt.Sprintf("droplets/%v/snapshot", id)
|
||||||
params := fmt.Sprintf("name=%s", name)
|
params := fmt.Sprintf("name=%v", name)
|
||||||
|
|
||||||
_, err := NewRequest(d, path, params)
|
_, err := NewRequest(d, path, params)
|
||||||
|
|
||||||
|
@ -104,17 +109,22 @@ func (d DigitalOceanClient) CreateSnapshot(id uint, name string) error {
|
||||||
|
|
||||||
// Returns DO's string representation of status "off" "new" "active" etc.
|
// Returns DO's string representation of status "off" "new" "active" etc.
|
||||||
func (d DigitalOceanClient) DropletStatus(id uint) (string, string, error) {
|
func (d DigitalOceanClient) DropletStatus(id uint) (string, string, error) {
|
||||||
path := fmt.Sprintf("droplets/%s", id)
|
path := fmt.Sprintf("droplets/%v", id)
|
||||||
|
|
||||||
body, err := NewRequest(d, path, "")
|
body, err := NewRequest(d, path, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ip string
|
||||||
|
|
||||||
// Read the droplet's "status"
|
// Read the droplet's "status"
|
||||||
droplet := body["droplet"].(map[string]interface{})
|
droplet := body["droplet"].(map[string]interface{})
|
||||||
status := droplet["status"].(string)
|
status := droplet["status"].(string)
|
||||||
ip := droplet["ip_address"].(string)
|
|
||||||
|
if droplet["ip_address"] != nil {
|
||||||
|
ip = droplet["ip_address"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
return ip, status, err
|
return ip, status, err
|
||||||
}
|
}
|
||||||
|
@ -123,11 +133,13 @@ func (d DigitalOceanClient) DropletStatus(id uint) (string, string, error) {
|
||||||
// the response.
|
// the response.
|
||||||
func NewRequest(d DigitalOceanClient, path string, params string) (map[string]interface{}, error) {
|
func NewRequest(d DigitalOceanClient, path string, params string) (map[string]interface{}, error) {
|
||||||
client := d.client
|
client := d.client
|
||||||
url := fmt.Sprintf("%s/%s?%s&client_id=%s&api_key=%s",
|
url := fmt.Sprintf("%v/%v?%v&client_id=%v&api_key=%v",
|
||||||
DIGITALOCEAN_API_URL, path, params, d.ClientID, d.APIKey)
|
DIGITALOCEAN_API_URL, path, params, d.ClientID, d.APIKey)
|
||||||
|
|
||||||
var decodedResponse map[string]interface{}
|
var decodedResponse map[string]interface{}
|
||||||
|
|
||||||
|
log.Printf("sending new request to digitalocean: %v", url)
|
||||||
|
|
||||||
resp, err := client.Get(url)
|
resp, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return decodedResponse, err
|
return decodedResponse, err
|
||||||
|
@ -140,13 +152,16 @@ func NewRequest(d DigitalOceanClient, path string, params string) (map[string]in
|
||||||
return decodedResponse, err
|
return decodedResponse, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &decodedResponse)
|
||||||
|
|
||||||
// Catch all non-200 status and return an error
|
// Catch all non-200 status and return an error
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
err = errors.New(fmt.Sprintf("recieved non-200 status from digitalocean: %d", resp.StatusCode))
|
err = errors.New(fmt.Sprintf("recieved non-200 status from digitalocean: %d", resp.StatusCode))
|
||||||
|
log.Printf("response from digital ocean: %v", decodedResponse)
|
||||||
return decodedResponse, err
|
return decodedResponse, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(body, &decodedResponse)
|
log.Printf("response from digital ocean: %v", decodedResponse)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return decodedResponse, err
|
return decodedResponse, err
|
||||||
|
@ -156,6 +171,7 @@ func NewRequest(d DigitalOceanClient, path string, params string) (map[string]in
|
||||||
status := decodedResponse["status"]
|
status := decodedResponse["status"]
|
||||||
if status != "OK" {
|
if status != "OK" {
|
||||||
err = errors.New(fmt.Sprintf("recieved non-OK status from digitalocean: %d", status))
|
err = errors.New(fmt.Sprintf("recieved non-OK status from digitalocean: %d", status))
|
||||||
|
log.Printf("response from digital ocean: %v", decodedResponse)
|
||||||
return decodedResponse, err
|
return decodedResponse, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,8 @@ func (b *Builder) Prepare(raw interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.ImageID == 0 {
|
if b.config.ImageID == 0 {
|
||||||
// Default to base image "Ubuntu 12.04 x64 Server"
|
// Default to base image "Ubuntu 12.04 x64 Server (id: 284203)"
|
||||||
b.config.ImageID = 2676
|
b.config.ImageID = 284203
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.SSHUsername == "" {
|
if b.config.SSHUsername == "" {
|
||||||
|
@ -131,8 +131,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
new(stepProvision),
|
new(stepProvision),
|
||||||
new(stepPowerOff),
|
new(stepPowerOff),
|
||||||
new(stepSnapshot),
|
new(stepSnapshot),
|
||||||
new(stepDestroyDroplet),
|
|
||||||
new(stepDestroySSHKey),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the steps
|
// Run the steps
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stepCreateDroplet struct {
|
type stepCreateDroplet struct {
|
||||||
|
@ -51,10 +52,16 @@ func (s *stepCreateDroplet) Cleanup(state map[string]interface{}) {
|
||||||
|
|
||||||
// Destroy the droplet we just created
|
// Destroy the droplet we just created
|
||||||
ui.Say("Destroying droplet...")
|
ui.Say("Destroying droplet...")
|
||||||
|
|
||||||
|
// Sleep arbitrarily before sending destroy request
|
||||||
|
// Otherwise we get "pending event" errors, even though there isn't
|
||||||
|
// one.
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
err := client.DestroyDroplet(s.dropletId)
|
err := client.DestroyDroplet(s.dropletId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(fmt.Sprintf(
|
ui.Error(fmt.Sprintf(
|
||||||
"Error destroying droplet. Please destroy it manually: %s", s.dropletId))
|
"Error destroying droplet. Please destroy it manually: %v", s.dropletId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,7 @@ package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cgl.tideland.biz/identifier"
|
"cgl.tideland.biz/identifier"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
@ -22,37 +18,80 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Creating temporary ssh key for droplet...")
|
ui.Say("Creating temporary ssh key for droplet...")
|
||||||
priv, err := rsa.GenerateKey(rand.Reader, 2014)
|
// priv, err := rsa.GenerateKey(rand.Reader, 2014)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
ui.Error(err.Error())
|
// ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
// return multistep.ActionHalt
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
// priv_der := x509.MarshalPKCS1PrivateKey(priv)
|
||||||
|
// priv_blk := pem.Block{
|
||||||
|
// Type: "RSA PRIVATE KEY",
|
||||||
|
// Headers: nil,
|
||||||
|
// Bytes: priv_der,
|
||||||
|
// }
|
||||||
|
|
||||||
// Set the pem formatted private key on the state for later
|
// Set the pem formatted private key on the state for later
|
||||||
priv_der := x509.MarshalPKCS1PrivateKey(priv)
|
// state["privateKey"] = string(pem.EncodeToMemory(&priv_blk))
|
||||||
priv_blk := pem.Block{
|
// log.Printf("PRIVATE KEY:\n\n%v\n\n", state["privateKey"])
|
||||||
Type: "RSA PRIVATE KEY",
|
|
||||||
Headers: nil,
|
|
||||||
Bytes: priv_der,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the public key for uploading to DO
|
// Create the public key for uploading to DO
|
||||||
pub := priv.PublicKey
|
// pub := priv.PublicKey
|
||||||
pub_der, err := x509.MarshalPKIXPublicKey(&pub)
|
|
||||||
if err != nil {
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
pub_blk := pem.Block{
|
|
||||||
Type: "PUBLIC KEY",
|
|
||||||
Headers: nil,
|
|
||||||
Bytes: pub_der,
|
|
||||||
}
|
|
||||||
pub_pem := string(pem.EncodeToMemory(&pub_blk))
|
|
||||||
|
|
||||||
name := fmt.Sprintf("packer %s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
// pub_bytes, err := x509.MarshalPKIXPublicKey(&pub)
|
||||||
|
|
||||||
keyId, err := client.CreateKey(name, pub_pem)
|
// pub_blk := pem.Block{
|
||||||
|
// Type: "RSA PUBLIC KEY",
|
||||||
|
// Headers: nil,
|
||||||
|
// Bytes: pub_bytes,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if err != nil {
|
||||||
|
// ui.Error(err.Error())
|
||||||
|
// return multistep.ActionHalt
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Encode the public key to base64
|
||||||
|
// pub_str := base64.StdEncoding.EncodeToString(pub_bytes)
|
||||||
|
// pub_str = "ssh-rsa " + pub_str
|
||||||
|
|
||||||
|
// log.Printf("PUBLIC KEY:\n\n%v\n\n", string(pem.EncodeToMemory(&pub_blk)))
|
||||||
|
// log.Printf("PUBLIC KEY BASE64:\n\n%v\n\n", pub_str)
|
||||||
|
|
||||||
|
pub_str := `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD29LZNMe0f7nOmdOIXDrF6eAmLZEk1yrnnsPI+xjLsnKxggMjdD3HvkBPXMdhakOj3pEF6DNtXbK43A7Pilezvu7y2awz+dxCavgUNtwaJkiTJw3C2qleNDDgrq7ZYLJ/wKmfhgPO4jZBej/8ONA0VjxemCNBPTTBeZ8FaeOpeUqopdhk78KGeGmUJ8Bvl8ACuYNdtJ5Y0BQCZkJT+g1ntTwHvuq/Vy/E2uCwJ2xV3vCDkLlqXVyksuVIcLJxTPtd5LdasD4WMQwoOPNdNMBLBG6ZBhXC/6kCVbMgzy5poSZ7r6BK0EA6b2EdAanaojYs3i52j6JeCIIrYtu9Ub173 jack@jose.local`
|
||||||
|
state["privateKey"] = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA9vS2TTHtH+5zpnTiFw6xengJi2RJNcq557DyPsYy7JysYIDI
|
||||||
|
3Q9x75AT1zHYWpDo96RBegzbV2yuNwOz4pXs77u8tmsM/ncQmr4FDbcGiZIkycNw
|
||||||
|
tqpXjQw4K6u2WCyf8Cpn4YDzuI2QXo//DjQNFY8XpgjQT00wXmfBWnjqXlKqKXYZ
|
||||||
|
O/ChnhplCfAb5fAArmDXbSeWNAUAmZCU/oNZ7U8B77qv1cvxNrgsCdsVd7wg5C5a
|
||||||
|
l1cpLLlSHCycUz7XeS3WrA+FjEMKDjzXTTASwRumQYVwv+pAlWzIM8uaaEme6+gS
|
||||||
|
tBAOm9hHQGp2qI2LN4udo+iXgiCK2LbvVG9e9wIDAQABAoIBABuBB6izTciHoyO/
|
||||||
|
0spknYmZQt7ebXTrPic6wtAQ/OzzShN5ZGWSacsXjc4ixAjaKMgj6BLyyZ8EAKcp
|
||||||
|
52ft8LSGgS8D3y+cDSJe1WtAnh7GQwihlrURZazU1pCukCFj3vA9mNI5rWs5gQG3
|
||||||
|
Id3wGCD1jdm1E5Yxb5ikD5nG67tTW5Pn4+tidsavTNsDLsks/pW/0EcPcKAS+TJ8
|
||||||
|
Zy15MsGGfHVVkxf+ldULIxxidAeplQhWuED6wkbuD3LQi6Kt4yElHS+UCATca8Fe
|
||||||
|
CvXNcQWrEHiYUvpyrvU3ybw7WEUUWFa/dctSZwmHvkvRD/bwJPf5M8sIIl8zlyuy
|
||||||
|
3YCIlSkCgYEA/ZqGOnYIK/bA/QVuyFkFkP3aJjOKJtH0RV9V5XVKSBlU1/Lm3DUZ
|
||||||
|
XVmp7JuWZHVhPxZa8tswj4x15dX+TwTvGdoUuqPC7K/UMOt6Qzk11o0+o2VRYU97
|
||||||
|
GzYyEDxGEnRqoZsc1922I6nBv8YqsW4WkMRhkFN4JNzLJBVXMTXcDCMCgYEA+Uob
|
||||||
|
VQfVF+7BfCOCNdSu9dqZoYRCyBm5JNEp5bqF1kiEbGw4FhJYp95Ix5ogD3Ug4aqe
|
||||||
|
8ylwUK86U2BhfkKmGQ5yf+6VNoTx3EPFaGrODIi82BUraYPyYEN10ZrR8Czy5X9g
|
||||||
|
1WC+WuboRgvTZs+grwnDVJwqQIOqIB2L0p+SdR0CgYEAokHavc7E/bP72CdAsSjb
|
||||||
|
+d+hUq3JJ3tPiY8suwnnQ+gJM72y3ZOPrf1vTfZiK9Y6KQ4ZlKaPFFkvGaVn95DV
|
||||||
|
ljnE54FddugsoDwZVqdk/egS+qIZhmQ/BLMRJvgZcTdQ/iLrOmYdYgX788JLkIg6
|
||||||
|
Ide0AI6XISavRl/tEIxARPcCgYEAlgh+6K8dFhlRA7iPPnyxjDAzdF0YoDuzDTCB
|
||||||
|
icy3jh747BQ5sTb7epSyssbU8tiooIjCv1A6U6UScmm4Y3gTZVMnoE1kKnra4Zk8
|
||||||
|
LzrQpgSJu3cKOKf78OnI+Ay4u1ciHPOLwQBHsIf2VWn6oo7lg1NZ5wtR9qAHfOqr
|
||||||
|
Y2k8iRUCgYBKQCtY4SNDuFb6+r5YSEFVfelCn6DJzNgTxO2mkUzzM7RcgejHbd+i
|
||||||
|
oqgnYXsFLJgm+NpN1eFpbs2RgAe8Zd4pKQNwJFJf0EbEP57sW3kujgFFEsPYJPOp
|
||||||
|
n8wFU32yrKgrVCftmCk1iI+WPfr1r9LKgKhb0sRX1+DsdWqfN6J7Sw==
|
||||||
|
-----END RSA PRIVATE KEY-----`
|
||||||
|
|
||||||
|
// The name of the public key on DO
|
||||||
|
name := fmt.Sprintf("packer-%s", hex.EncodeToString(identifier.NewUUID().Raw()))
|
||||||
|
|
||||||
|
// Create the key!
|
||||||
|
keyId, err := client.CreateKey(name, pub_str)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
@ -66,7 +105,6 @@ func (s *stepCreateSSHKey) Run(state map[string]interface{}) multistep.StepActio
|
||||||
|
|
||||||
// Remember some state for the future
|
// Remember some state for the future
|
||||||
state["ssh_key_id"] = keyId
|
state["ssh_key_id"] = keyId
|
||||||
state["privateKey"] = string(pem.EncodeToMemory(&priv_blk))
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
@ -83,7 +121,8 @@ func (s *stepCreateSSHKey) Cleanup(state map[string]interface{}) {
|
||||||
ui.Say("Deleting temporary ssh key...")
|
ui.Say("Deleting temporary ssh key...")
|
||||||
err := client.DestroyKey(s.keyId)
|
err := client.DestroyKey(s.keyId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Error cleaning up ssh key: %v", err.Error())
|
||||||
ui.Error(fmt.Sprintf(
|
ui.Error(fmt.Sprintf(
|
||||||
"Error cleaning up ssh key. Please delete the key manually: %s", s.keyId))
|
"Error cleaning up ssh key. Please delete the key manually: %v", s.keyId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package digitalocean
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/mitchellh/multistep"
|
|
||||||
"github.com/mitchellh/packer/packer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type stepDestroyDroplet struct{}
|
|
||||||
|
|
||||||
func (s *stepDestroyDroplet) Run(state map[string]interface{}) multistep.StepAction {
|
|
||||||
client := state["client"].(*DigitalOceanClient)
|
|
||||||
ui := state["ui"].(packer.Ui)
|
|
||||||
dropletId := state["droplet_id"].(uint)
|
|
||||||
|
|
||||||
ui.Say("Destroying droplet...")
|
|
||||||
|
|
||||||
err := client.DestroyDroplet(dropletId)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepDestroyDroplet) Cleanup(state map[string]interface{}) {
|
|
||||||
// no cleanup
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package digitalocean
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/mitchellh/multistep"
|
|
||||||
"github.com/mitchellh/packer/packer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type stepDestroySSHKey struct{}
|
|
||||||
|
|
||||||
func (s *stepDestroySSHKey) Run(state map[string]interface{}) multistep.StepAction {
|
|
||||||
client := state["client"].(*DigitalOceanClient)
|
|
||||||
ui := state["ui"].(packer.Ui)
|
|
||||||
sshKeyId := state["ssh_key_id"].(uint)
|
|
||||||
|
|
||||||
ui.Say("Destroying temporary ssh key...")
|
|
||||||
|
|
||||||
err := client.DestroyKey(sshKeyId)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepDestroySSHKey) Cleanup(state map[string]interface{}) {
|
|
||||||
// no cleanup
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ package digitalocean
|
||||||
import (
|
import (
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stepPowerOff struct{}
|
type stepPowerOff struct{}
|
||||||
|
@ -12,6 +13,11 @@ func (s *stepPowerOff) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
dropletId := state["droplet_id"].(uint)
|
dropletId := state["droplet_id"].(uint)
|
||||||
|
|
||||||
|
// Sleep arbitrarily before sending power off request
|
||||||
|
// Otherwise we get "pending event" errors, even though there isn't
|
||||||
|
// one.
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
// Poweroff the droplet so it can be snapshot
|
// Poweroff the droplet so it can be snapshot
|
||||||
err := client.PowerOffDroplet(dropletId)
|
err := client.PowerOffDroplet(dropletId)
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,6 @@ func waitForDropletState(desiredState string, dropletId uint, client *DigitalOce
|
||||||
go func() {
|
go func() {
|
||||||
attempts := 0
|
attempts := 0
|
||||||
for {
|
for {
|
||||||
select {
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|
||||||
log.Printf("Checking droplet status... (attempt: %d)", attempts)
|
log.Printf("Checking droplet status... (attempt: %d)", attempts)
|
||||||
|
@ -33,8 +29,8 @@ func waitForDropletState(desiredState string, dropletId uint, client *DigitalOce
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait a second in between
|
// Wait 3 seconds in between
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
active <- true
|
active <- true
|
||||||
|
@ -53,9 +49,6 @@ ActiveWaitLoop:
|
||||||
case <-timeout:
|
case <-timeout:
|
||||||
err := errors.New("Timeout while waiting to for droplet to become active")
|
err := errors.New("Timeout while waiting to for droplet to become active")
|
||||||
return err
|
return err
|
||||||
case <-time.After(1 * time.Second):
|
|
||||||
err := errors.New("Interrupt detected, quitting waiting for droplet")
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue