builder/digitalocean: Implement Artifact destroy
/cc @pearkes
This commit is contained in:
parent
0a90d3e791
commit
264e59d75d
|
@ -8,6 +8,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
@ -16,6 +17,16 @@ import (
|
|||
|
||||
const DIGITALOCEAN_API_URL = "https://api.digitalocean.com"
|
||||
|
||||
type Image struct {
|
||||
Id uint
|
||||
Name string
|
||||
Distribution string
|
||||
}
|
||||
|
||||
type ImagesResp struct {
|
||||
Images []Image
|
||||
}
|
||||
|
||||
type DigitalOceanClient struct {
|
||||
// The http client for communicating
|
||||
client *http.Client
|
||||
|
@ -107,6 +118,28 @@ func (d DigitalOceanClient) CreateSnapshot(id uint, name string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Returns all available images.
|
||||
func (d DigitalOceanClient) Images() ([]Image, error) {
|
||||
resp, err := NewRequest(d, "images", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result ImagesResp
|
||||
if err := mapstructure.Decode(resp, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.Images, nil
|
||||
}
|
||||
|
||||
// Destroys an image by its ID.
|
||||
func (d DigitalOceanClient) DestroyImage(id uint) error {
|
||||
path := fmt.Sprintf("images/%d/destroy", id)
|
||||
_, err := NewRequest(d, path, "")
|
||||
return err
|
||||
}
|
||||
|
||||
// Returns DO's string representation of status "off" "new" "active" etc.
|
||||
func (d DigitalOceanClient) DropletStatus(id uint) (string, string, error) {
|
||||
path := fmt.Sprintf("droplets/%v", id)
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
package digitalocean
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Artifact struct {
|
||||
// The name of the snapshot
|
||||
snapshotName string
|
||||
|
||||
// The ID of the image
|
||||
snapshotId uint
|
||||
|
||||
// The client for making API calls
|
||||
client *DigitalOceanClient
|
||||
}
|
||||
|
||||
func (*Artifact) BuilderId() string {
|
||||
|
@ -28,5 +34,6 @@ func (a *Artifact) String() string {
|
|||
}
|
||||
|
||||
func (a *Artifact) Destroy() error {
|
||||
return errors.New("not implemented yet")
|
||||
log.Printf("Destroying image: %d", a.snapshotId)
|
||||
return a.client.DestroyImage(a.snapshotId)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestArtifact_Impl(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestArtifactString(t *testing.T) {
|
||||
a := &Artifact{"packer-foobar"}
|
||||
a := &Artifact{"packer-foobar", 42, nil}
|
||||
expected := "A snapshot was created: packer-foobar"
|
||||
|
||||
if a.String() != expected {
|
||||
|
|
|
@ -184,7 +184,18 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
|
||||
b.runner.Run(state)
|
||||
|
||||
return &Artifact{b.config.SnapshotName}, nil
|
||||
if _, ok := state["snapshot_name"]; !ok {
|
||||
log.Println("Failed to find snapshot_name in state. Bug?")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
artifact := &Artifact{
|
||||
snapshotName: state["snapshot_name"].(string),
|
||||
snapshotId: state["snapshot_image_id"].(uint),
|
||||
client: client,
|
||||
}
|
||||
|
||||
return artifact, nil
|
||||
}
|
||||
|
||||
func (b *Builder) Cancel() {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
)
|
||||
|
||||
type stepSnapshot struct{}
|
||||
|
@ -15,23 +16,44 @@ func (s *stepSnapshot) Run(state map[string]interface{}) multistep.StepAction {
|
|||
dropletId := state["droplet_id"].(uint)
|
||||
|
||||
ui.Say(fmt.Sprintf("Creating snapshot: %v", c.SnapshotName))
|
||||
|
||||
err := client.CreateSnapshot(dropletId, c.SnapshotName)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say("Waiting for snapshot to complete...")
|
||||
|
||||
err = waitForDropletState("active", dropletId, client)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Looking up snapshot ID for snapshot: %s", c.SnapshotName)
|
||||
images, err := client.Images()
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
var imageId uint
|
||||
for _, image := range images {
|
||||
if image.Name == c.SnapshotName {
|
||||
imageId = image.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if imageId == 0 {
|
||||
ui.Error("Couldn't find snapshot to get the image ID. Bug?")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("Snapshot image ID: %d", imageId)
|
||||
|
||||
state["snapshot_image_id"] = imageId
|
||||
state["snapshot_name"] = c.SnapshotName
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue