Wait for snapshot transfer and change artifact output

This commit is contained in:
Luke Farnell 2017-05-16 10:38:53 -04:00 committed by Matthew Hooker
parent 4f5d3face2
commit abf2e618b5
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
4 changed files with 64 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt"
"log"
"strconv"
"strings"
"github.com/digitalocean/godo"
)
@ -17,7 +18,7 @@ type Artifact struct {
snapshotId int
// The name of the region
regionName string
regionNames []string
// The client for making API calls
client *godo.Client
@ -33,11 +34,11 @@ func (*Artifact) Files() []string {
}
func (a *Artifact) Id() string {
return fmt.Sprintf("%s:%s", a.regionName, strconv.FormatUint(uint64(a.snapshotId), 10))
return fmt.Sprintf("%s:%s", strings.Join(a.regionNames[:], ","), strconv.FormatUint(uint64(a.snapshotId), 10))
}
func (a *Artifact) String() string {
return fmt.Sprintf("A snapshot was created: '%v' (ID: %v) in region '%v'", a.snapshotName, a.snapshotId, a.regionName)
return fmt.Sprintf("A snapshot was created: '%v' (ID: %v) in regions '%v'", a.snapshotName, a.snapshotId, strings.Join(a.regionNames[:], ","))
}
func (a *Artifact) State(name string) interface{} {

View File

@ -89,7 +89,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
artifact := &Artifact{
snapshotName: state.Get("snapshot_name").(string),
snapshotId: state.Get("snapshot_image_id").(int),
regionName: state.Get("region").(string),
regionNames: state.Get("regions").([]string),
client: client,
}

View File

@ -90,6 +90,14 @@ func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt
}
ui.Say(fmt.Sprintf("Transfering Snapshot ID: %d", imageTransfer.ID))
if err := waitForImageState(godo.ActionCompleted, imageTransfer.ID, action.ID,
client, 20*time.Minute); err != nil {
// If we get an error the first time, actually report it
err := fmt.Errorf("Error waiting for snapshot transfer: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
@ -106,7 +114,7 @@ func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
log.Printf("Snapshot image ID: %d", imageId)
state.Put("snapshot_image_id", imageId)
state.Put("snapshot_name", c.SnapshotName)
state.Put("region", c.Region)
state.Put("regions", c.SnapshotRegions)
return multistep.ActionContinue
}

View File

@ -157,3 +157,53 @@ func waitForActionState(
return err
}
}
// waitForImageState simply blocks until the image action is in
// a state we expect, while eventually timing out.
func waitForImageState(
desiredState string, imageId, actionId int,
client *godo.Client, timeout time.Duration) error {
done := make(chan struct{})
defer close(done)
result := make(chan error, 1)
go func() {
attempts := 0
for {
attempts += 1
log.Printf("Checking action status... (attempt: %d)", attempts)
action, _, err := client.ImageActions.Get(context.TODO(), imageId, actionId)
if err != nil {
result <- err
return
}
if action.Status == desiredState {
result <- nil
return
}
// Wait 3 seconds in between
time.Sleep(3 * time.Second)
// Verify we shouldn't exit
select {
case <-done:
// We finished, so just exit the goroutine
return
default:
// Keep going
}
}
}()
log.Printf("Waiting for up to %d seconds for image transter to become %s", timeout/time.Second, desiredState)
select {
case err := <-result:
return err
case <-time.After(timeout):
err := fmt.Errorf("Timeout while waiting to for image transter to become '%s'", desiredState)
return err
}
}