github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/amazon/ebssurrogate/step_snapshot_new_root.go (about)

     1  package ebssurrogate
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/service/ec2"
     9  	awscommon "github.com/hashicorp/packer/builder/amazon/common"
    10  	"github.com/hashicorp/packer/packer"
    11  	"github.com/mitchellh/multistep"
    12  )
    13  
    14  // StepSnapshotNewRootVolume creates a snapshot of the created volume.
    15  //
    16  // Produces:
    17  //   snapshot_id string - ID of the created snapshot
    18  type StepSnapshotNewRootVolume struct {
    19  	NewRootMountPoint string
    20  	snapshotId        string
    21  }
    22  
    23  func (s *StepSnapshotNewRootVolume) Run(state multistep.StateBag) multistep.StepAction {
    24  	ec2conn := state.Get("ec2").(*ec2.EC2)
    25  	ui := state.Get("ui").(packer.Ui)
    26  	instance := state.Get("instance").(*ec2.Instance)
    27  
    28  	var newRootVolume string
    29  	for _, volume := range instance.BlockDeviceMappings {
    30  		if *volume.DeviceName == s.NewRootMountPoint {
    31  			newRootVolume = *volume.Ebs.VolumeId
    32  		}
    33  	}
    34  
    35  	ui.Say(fmt.Sprintf("Creating snapshot of EBS Volume %s...", newRootVolume))
    36  	description := fmt.Sprintf("Packer: %s", time.Now().String())
    37  
    38  	createSnapResp, err := ec2conn.CreateSnapshot(&ec2.CreateSnapshotInput{
    39  		VolumeId:    &newRootVolume,
    40  		Description: &description,
    41  	})
    42  	if err != nil {
    43  		err := fmt.Errorf("Error creating snapshot: %s", err)
    44  		state.Put("error", err)
    45  		ui.Error(err.Error())
    46  		return multistep.ActionHalt
    47  	}
    48  
    49  	// Set the snapshot ID so we can delete it later
    50  	s.snapshotId = *createSnapResp.SnapshotId
    51  	ui.Message(fmt.Sprintf("Snapshot ID: %s", s.snapshotId))
    52  
    53  	// Wait for the snapshot to be ready
    54  	stateChange := awscommon.StateChangeConf{
    55  		Pending:   []string{"pending"},
    56  		StepState: state,
    57  		Target:    "completed",
    58  		Refresh: func() (interface{}, string, error) {
    59  			resp, err := ec2conn.DescribeSnapshots(&ec2.DescribeSnapshotsInput{SnapshotIds: []*string{&s.snapshotId}})
    60  			if err != nil {
    61  				return nil, "", err
    62  			}
    63  
    64  			if len(resp.Snapshots) == 0 {
    65  				return nil, "", errors.New("No snapshots found.")
    66  			}
    67  
    68  			s := resp.Snapshots[0]
    69  			return s, *s.State, nil
    70  		},
    71  	}
    72  
    73  	_, err = awscommon.WaitForState(&stateChange)
    74  	if err != nil {
    75  		err := fmt.Errorf("Error waiting for snapshot: %s", err)
    76  		state.Put("error", err)
    77  		ui.Error(err.Error())
    78  		return multistep.ActionHalt
    79  	}
    80  
    81  	state.Put("snapshot_id", s.snapshotId)
    82  	return multistep.ActionContinue
    83  }
    84  
    85  func (s *StepSnapshotNewRootVolume) Cleanup(state multistep.StateBag) {
    86  	if s.snapshotId == "" {
    87  		return
    88  	}
    89  
    90  	_, cancelled := state.GetOk(multistep.StateCancelled)
    91  	_, halted := state.GetOk(multistep.StateHalted)
    92  
    93  	if cancelled || halted {
    94  		ec2conn := state.Get("ec2").(*ec2.EC2)
    95  		ui := state.Get("ui").(packer.Ui)
    96  		ui.Say("Removing snapshot since we cancelled or halted...")
    97  		_, err := ec2conn.DeleteSnapshot(&ec2.DeleteSnapshotInput{SnapshotId: &s.snapshotId})
    98  		if err != nil {
    99  			ui.Error(fmt.Sprintf("Error: %s", err))
   100  		}
   101  	}
   102  }