github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/ebssurrogate/step_snapshot_volumes.go (about) 1 package ebssurrogate 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/aws/aws-sdk-go/service/ec2" 10 multierror "github.com/hashicorp/go-multierror" 11 awscommon "github.com/hashicorp/packer/builder/amazon/common" 12 "github.com/hashicorp/packer/helper/multistep" 13 "github.com/hashicorp/packer/packer" 14 ) 15 16 // StepSnapshotVolumes creates snapshots of the created volumes. 17 // 18 // Produces: 19 // snapshot_ids map[string]string - IDs of the created snapshots 20 type StepSnapshotVolumes struct { 21 LaunchDevices []*ec2.BlockDeviceMapping 22 snapshotIds map[string]string 23 } 24 25 func (s *StepSnapshotVolumes) snapshotVolume(ctx context.Context, deviceName string, state multistep.StateBag) error { 26 ec2conn := state.Get("ec2").(*ec2.EC2) 27 ui := state.Get("ui").(packer.Ui) 28 instance := state.Get("instance").(*ec2.Instance) 29 30 var volumeId string 31 for _, volume := range instance.BlockDeviceMappings { 32 if *volume.DeviceName == deviceName { 33 volumeId = *volume.Ebs.VolumeId 34 } 35 } 36 if volumeId == "" { 37 return fmt.Errorf("Volume ID for device %s not found", deviceName) 38 } 39 40 ui.Say(fmt.Sprintf("Creating snapshot of EBS Volume %s...", volumeId)) 41 description := fmt.Sprintf("Packer: %s", time.Now().String()) 42 43 createSnapResp, err := ec2conn.CreateSnapshot(&ec2.CreateSnapshotInput{ 44 VolumeId: &volumeId, 45 Description: &description, 46 }) 47 if err != nil { 48 return err 49 } 50 51 // Set the snapshot ID so we can delete it later 52 s.snapshotIds[deviceName] = *createSnapResp.SnapshotId 53 54 // Wait for snapshot to be created 55 err = awscommon.WaitUntilSnapshotDone(ctx, ec2conn, *createSnapResp.SnapshotId) 56 return err 57 } 58 59 func (s *StepSnapshotVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { 60 ui := state.Get("ui").(packer.Ui) 61 62 s.snapshotIds = map[string]string{} 63 64 var wg sync.WaitGroup 65 var errs *multierror.Error 66 for _, device := range s.LaunchDevices { 67 wg.Add(1) 68 go func(device *ec2.BlockDeviceMapping) { 69 defer wg.Done() 70 if err := s.snapshotVolume(ctx, *device.DeviceName, state); err != nil { 71 errs = multierror.Append(errs, err) 72 } 73 }(device) 74 } 75 76 wg.Wait() 77 78 if errs != nil { 79 state.Put("error", errs) 80 ui.Error(errs.Error()) 81 return multistep.ActionHalt 82 } 83 84 state.Put("snapshot_ids", s.snapshotIds) 85 return multistep.ActionContinue 86 } 87 88 func (s *StepSnapshotVolumes) Cleanup(state multistep.StateBag) { 89 if len(s.snapshotIds) == 0 { 90 return 91 } 92 93 _, cancelled := state.GetOk(multistep.StateCancelled) 94 _, halted := state.GetOk(multistep.StateHalted) 95 96 if cancelled || halted { 97 ec2conn := state.Get("ec2").(*ec2.EC2) 98 ui := state.Get("ui").(packer.Ui) 99 ui.Say("Removing snapshots since we cancelled or halted...") 100 for _, snapshotId := range s.snapshotIds { 101 _, err := ec2conn.DeleteSnapshot(&ec2.DeleteSnapshotInput{SnapshotId: &snapshotId}) 102 if err != nil { 103 ui.Error(fmt.Sprintf("Error: %s", err)) 104 } 105 } 106 } 107 }