github.com/phobos182/packer@v0.2.3-0.20130819023704-c84d2aeffc68/builder/amazon/chroot/step_attach_volume.go (about) 1 package chroot 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/mitchellh/goamz/ec2" 7 "github.com/mitchellh/multistep" 8 awscommon "github.com/mitchellh/packer/builder/amazon/common" 9 "github.com/mitchellh/packer/packer" 10 "strings" 11 ) 12 13 // StepAttachVolume attaches the previously created volume to an 14 // available device location. 15 // 16 // Produces: 17 // device string - The location where the volume was attached. 18 // attach_cleanup CleanupFunc 19 type StepAttachVolume struct { 20 attached bool 21 volumeId string 22 } 23 24 func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepAction { 25 ec2conn := state["ec2"].(*ec2.EC2) 26 device := state["device"].(string) 27 instance := state["instance"].(*ec2.Instance) 28 ui := state["ui"].(packer.Ui) 29 volumeId := state["volume_id"].(string) 30 31 // For the API call, it expects "sd" prefixed devices. 32 attachVolume := strings.Replace(device, "/xvd", "/sd", 1) 33 34 ui.Say(fmt.Sprintf("Attaching the root volume to %s", attachVolume)) 35 _, err := ec2conn.AttachVolume(volumeId, instance.InstanceId, attachVolume) 36 if err != nil { 37 err := fmt.Errorf("Error attaching volume: %s", err) 38 state["error"] = err 39 ui.Error(err.Error()) 40 return multistep.ActionHalt 41 } 42 43 // Mark that we attached it so we can detach it later 44 s.attached = true 45 s.volumeId = volumeId 46 47 // Wait for the volume to become attached 48 stateChange := awscommon.StateChangeConf{ 49 Conn: ec2conn, 50 Pending: []string{"attaching"}, 51 StepState: state, 52 Target: "attached", 53 Refresh: func() (interface{}, string, error) { 54 resp, err := ec2conn.Volumes([]string{volumeId}, ec2.NewFilter()) 55 if err != nil { 56 return nil, "", err 57 } 58 59 if len(resp.Volumes[0].Attachments) == 0 { 60 return nil, "", errors.New("No attachments on volume.") 61 } 62 63 return nil, resp.Volumes[0].Attachments[0].Status, nil 64 }, 65 } 66 67 _, err = awscommon.WaitForState(&stateChange) 68 if err != nil { 69 err := fmt.Errorf("Error waiting for volume: %s", err) 70 state["error"] = err 71 ui.Error(err.Error()) 72 return multistep.ActionHalt 73 } 74 75 state["attach_cleanup"] = s 76 return multistep.ActionContinue 77 } 78 79 func (s *StepAttachVolume) Cleanup(state map[string]interface{}) { 80 ui := state["ui"].(packer.Ui) 81 if err := s.CleanupFunc(state); err != nil { 82 ui.Error(err.Error()) 83 } 84 } 85 86 func (s *StepAttachVolume) CleanupFunc(state map[string]interface{}) error { 87 if !s.attached { 88 return nil 89 } 90 91 ec2conn := state["ec2"].(*ec2.EC2) 92 ui := state["ui"].(packer.Ui) 93 94 ui.Say("Detaching EBS volume...") 95 _, err := ec2conn.DetachVolume(s.volumeId) 96 if err != nil { 97 return fmt.Errorf("Error detaching EBS volume: %s", err) 98 } 99 100 s.attached = false 101 102 // Wait for the volume to detach 103 stateChange := awscommon.StateChangeConf{ 104 Conn: ec2conn, 105 Pending: []string{"attaching", "attached", "detaching"}, 106 StepState: state, 107 Target: "detached", 108 Refresh: func() (interface{}, string, error) { 109 resp, err := ec2conn.Volumes([]string{s.volumeId}, ec2.NewFilter()) 110 if err != nil { 111 return nil, "", err 112 } 113 114 state := "detached" 115 if len(resp.Volumes[0].Attachments) > 0 { 116 state = resp.Volumes[0].Attachments[0].Status 117 } 118 119 return nil, state, nil 120 }, 121 } 122 123 _, err = awscommon.WaitForState(&stateChange) 124 if err != nil { 125 return fmt.Errorf("Error waiting for volume: %s", err) 126 } 127 128 return nil 129 }