diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index d8665881b..840ac1561 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -143,6 +143,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &StepCopyFiles{}, &StepChrootProvision{}, &StepEarlyCleanup{}, + &StepSnapshot{}, } // Run! diff --git a/builder/amazon/chroot/step_snapshot.go b/builder/amazon/chroot/step_snapshot.go new file mode 100644 index 000000000..837543ec8 --- /dev/null +++ b/builder/amazon/chroot/step_snapshot.go @@ -0,0 +1,87 @@ +package chroot + +import ( + "errors" + "fmt" + "github.com/mitchellh/goamz/ec2" + "github.com/mitchellh/multistep" + awscommon "github.com/mitchellh/packer/builder/amazon/common" + "github.com/mitchellh/packer/packer" +) + +// StepSnapshot creates a snapshot of the created volume. +// +// Produces: +// snapshot_id string - ID of the created snapshot +type StepSnapshot struct { + snapshotId string +} + +func (s *StepSnapshot) Run(state map[string]interface{}) multistep.StepAction { + ec2conn := state["ec2"].(*ec2.EC2) + ui := state["ui"].(packer.Ui) + volumeId := state["volume_id"].(string) + + ui.Say("Creating snapshot...") + createSnapResp, err := ec2conn.CreateSnapshot(volumeId, "") + if err != nil { + err := fmt.Errorf("Error creating snapshot: %s", err) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Set the snapshot ID so we can delete it later + s.snapshotId = createSnapResp.Id + ui.Message(fmt.Sprintf("Snapshot ID: %s", s.snapshotId)) + + // Wait for the snapshot to be ready + stateChange := awscommon.StateChangeConf{ + Conn: ec2conn, + Pending: []string{"pending"}, + StepState: state, + Target: "completed", + Refresh: func() (interface{}, string, error) { + resp, err := ec2conn.Snapshots([]string{s.snapshotId}, ec2.NewFilter()) + if err != nil { + return nil, "", err + } + + if len(resp.Snapshots) == 0 { + return nil, "", errors.New("No snapshots found.") + } + + return nil, resp.Snapshots[0].Status, nil + }, + } + + _, err = awscommon.WaitForState(&stateChange) + if err != nil { + err := fmt.Errorf("Error waiting for snapshot: %s", err) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + state["snapshot_id"] = s.snapshotId + return multistep.ActionContinue +} + +func (s *StepSnapshot) Cleanup(state map[string]interface{}) { + if s.snapshotId == "" { + return + } + + _, cancelled := state[multistep.StateCancelled] + _, halted := state[multistep.StateHalted] + + if cancelled || halted { + ec2conn := state["ec2"].(*ec2.EC2) + ui := state["ui"].(packer.Ui) + ui.Say("Removing snapshot since we cancelled or halted...") + _, err := ec2conn.DeleteSnapshots([]string{s.snapshotId}) + if err != nil { + ui.Error(fmt.Sprintf("Error: %s", err)) + } + } +}