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" "fmt"
"log" "log"
"strconv" "strconv"
"strings"
"github.com/digitalocean/godo" "github.com/digitalocean/godo"
) )
@ -17,7 +18,7 @@ type Artifact struct {
snapshotId int snapshotId int
// The name of the region // The name of the region
regionName string regionNames []string
// The client for making API calls // The client for making API calls
client *godo.Client client *godo.Client
@ -33,11 +34,11 @@ func (*Artifact) Files() []string {
} }
func (a *Artifact) Id() 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 { 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{} { 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{ artifact := &Artifact{
snapshotName: state.Get("snapshot_name").(string), snapshotName: state.Get("snapshot_name").(string),
snapshotId: state.Get("snapshot_image_id").(int), snapshotId: state.Get("snapshot_image_id").(int),
regionName: state.Get("region").(string), regionNames: state.Get("regions").([]string),
client: client, client: client,
} }

View File

@ -90,6 +90,14 @@ func (s *stepSnapshot) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt return multistep.ActionHalt
} }
ui.Say(fmt.Sprintf("Transfering Snapshot ID: %d", imageTransfer.ID)) 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) log.Printf("Snapshot image ID: %d", imageId)
state.Put("snapshot_image_id", imageId) state.Put("snapshot_image_id", imageId)
state.Put("snapshot_name", c.SnapshotName) state.Put("snapshot_name", c.SnapshotName)
state.Put("region", c.Region) state.Put("regions", c.SnapshotRegions)
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -157,3 +157,53 @@ func waitForActionState(
return err 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
}
}