github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/chroot/step_attach_volume.go (about) 1 package chroot 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/service/ec2" 10 awscommon "github.com/hashicorp/packer/builder/amazon/common" 11 "github.com/hashicorp/packer/helper/multistep" 12 "github.com/hashicorp/packer/packer" 13 ) 14 15 // StepAttachVolume attaches the previously created volume to an 16 // available device location. 17 // 18 // Produces: 19 // device string - The location where the volume was attached. 20 // attach_cleanup CleanupFunc 21 type StepAttachVolume struct { 22 attached bool 23 volumeId string 24 } 25 26 func (s *StepAttachVolume) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { 27 ec2conn := state.Get("ec2").(*ec2.EC2) 28 device := state.Get("device").(string) 29 instance := state.Get("instance").(*ec2.Instance) 30 ui := state.Get("ui").(packer.Ui) 31 volumeId := state.Get("volume_id").(string) 32 33 // For the API call, it expects "sd" prefixed devices. 34 attachVolume := strings.Replace(device, "/xvd", "/sd", 1) 35 36 ui.Say(fmt.Sprintf("Attaching the root volume to %s", attachVolume)) 37 _, err := ec2conn.AttachVolume(&ec2.AttachVolumeInput{ 38 InstanceId: instance.InstanceId, 39 VolumeId: &volumeId, 40 Device: &attachVolume, 41 }) 42 if err != nil { 43 err := fmt.Errorf("Error attaching volume: %s", err) 44 state.Put("error", err) 45 ui.Error(err.Error()) 46 return multistep.ActionHalt 47 } 48 49 // Mark that we attached it so we can detach it later 50 s.attached = true 51 s.volumeId = volumeId 52 53 // Wait for the volume to become attached 54 err = awscommon.WaitUntilVolumeAttached(ctx, ec2conn, s.volumeId) 55 if err != nil { 56 err := fmt.Errorf("Error waiting for volume: %s", err) 57 state.Put("error", err) 58 ui.Error(err.Error()) 59 return multistep.ActionHalt 60 } 61 62 state.Put("attach_cleanup", s) 63 return multistep.ActionContinue 64 } 65 66 func (s *StepAttachVolume) Cleanup(state multistep.StateBag) { 67 ui := state.Get("ui").(packer.Ui) 68 if err := s.CleanupFunc(state); err != nil { 69 ui.Error(err.Error()) 70 } 71 } 72 73 func (s *StepAttachVolume) CleanupFunc(state multistep.StateBag) error { 74 if !s.attached { 75 return nil 76 } 77 78 ec2conn := state.Get("ec2").(*ec2.EC2) 79 ui := state.Get("ui").(packer.Ui) 80 81 ui.Say("Detaching EBS volume...") 82 _, err := ec2conn.DetachVolume(&ec2.DetachVolumeInput{VolumeId: &s.volumeId}) 83 if err != nil { 84 return fmt.Errorf("Error detaching EBS volume: %s", err) 85 } 86 87 s.attached = false 88 89 // Wait for the volume to detach 90 err = awscommon.WaitUntilVolumeDetached(aws.BackgroundContext(), ec2conn, s.volumeId) 91 if err != nil { 92 return fmt.Errorf("Error waiting for volume: %s", err) 93 } 94 95 return nil 96 }