github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/chroot/step_mount_device.go (about) 1 package chroot 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "log" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/aws/aws-sdk-go/service/ec2" 13 "github.com/hashicorp/packer/helper/multistep" 14 "github.com/hashicorp/packer/packer" 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 type mountPathData struct { 19 Device string 20 } 21 22 // StepMountDevice mounts the attached device. 23 // 24 // Produces: 25 // mount_path string - The location where the volume was mounted. 26 // mount_device_cleanup CleanupFunc - To perform early cleanup 27 type StepMountDevice struct { 28 MountOptions []string 29 MountPartition string 30 31 mountPath string 32 } 33 34 func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 35 config := state.Get("config").(*Config) 36 ui := state.Get("ui").(packer.Ui) 37 device := state.Get("device").(string) 38 if config.NVMEDevicePath != "" { 39 // customizable device path for mounting NVME block devices on c5 and m5 HVM 40 device = config.NVMEDevicePath 41 } 42 wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) 43 44 var virtualizationType string 45 if config.FromScratch { 46 virtualizationType = config.AMIVirtType 47 } else { 48 image := state.Get("source_image").(*ec2.Image) 49 virtualizationType = *image.VirtualizationType 50 log.Printf("Source image virtualization type is: %s", virtualizationType) 51 } 52 53 ctx := config.ctx 54 55 ctx.Data = &mountPathData{Device: filepath.Base(device)} 56 mountPath, err := interpolate.Render(config.MountPath, &ctx) 57 58 if err != nil { 59 err := fmt.Errorf("Error preparing mount directory: %s", err) 60 state.Put("error", err) 61 ui.Error(err.Error()) 62 return multistep.ActionHalt 63 } 64 65 mountPath, err = filepath.Abs(mountPath) 66 if err != nil { 67 err := fmt.Errorf("Error preparing mount directory: %s", err) 68 state.Put("error", err) 69 ui.Error(err.Error()) 70 return multistep.ActionHalt 71 } 72 73 log.Printf("Mount path: %s", mountPath) 74 75 if err := os.MkdirAll(mountPath, 0755); err != nil { 76 err := fmt.Errorf("Error creating mount directory: %s", err) 77 state.Put("error", err) 78 ui.Error(err.Error()) 79 return multistep.ActionHalt 80 } 81 82 deviceMount := device 83 84 if virtualizationType == "hvm" && s.MountPartition != "0" { 85 deviceMount = fmt.Sprintf("%s%s", device, s.MountPartition) 86 } 87 state.Put("deviceMount", deviceMount) 88 89 ui.Say("Mounting the root device...") 90 stderr := new(bytes.Buffer) 91 92 // build mount options from mount_options config, useful for nouuid options 93 // or other specific device type settings for mount 94 opts := "" 95 if len(s.MountOptions) > 0 { 96 opts = "-o " + strings.Join(s.MountOptions, " -o ") 97 } 98 mountCommand, err := wrappedCommand( 99 fmt.Sprintf("mount %s %s %s", opts, deviceMount, mountPath)) 100 if err != nil { 101 err := fmt.Errorf("Error creating mount command: %s", err) 102 state.Put("error", err) 103 ui.Error(err.Error()) 104 return multistep.ActionHalt 105 } 106 log.Printf("[DEBUG] (step mount) mount command is %s", mountCommand) 107 cmd := ShellCommand(mountCommand) 108 cmd.Stderr = stderr 109 if err := cmd.Run(); err != nil { 110 err := fmt.Errorf( 111 "Error mounting root volume: %s\nStderr: %s", err, stderr.String()) 112 state.Put("error", err) 113 ui.Error(err.Error()) 114 return multistep.ActionHalt 115 } 116 117 // Set the mount path so we remember to unmount it later 118 s.mountPath = mountPath 119 state.Put("mount_path", s.mountPath) 120 state.Put("mount_device_cleanup", s) 121 122 return multistep.ActionContinue 123 } 124 125 func (s *StepMountDevice) Cleanup(state multistep.StateBag) { 126 ui := state.Get("ui").(packer.Ui) 127 if err := s.CleanupFunc(state); err != nil { 128 ui.Error(err.Error()) 129 } 130 } 131 132 func (s *StepMountDevice) CleanupFunc(state multistep.StateBag) error { 133 if s.mountPath == "" { 134 return nil 135 } 136 137 ui := state.Get("ui").(packer.Ui) 138 wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) 139 140 ui.Say("Unmounting the root device...") 141 unmountCommand, err := wrappedCommand(fmt.Sprintf("umount %s", s.mountPath)) 142 if err != nil { 143 return fmt.Errorf("Error creating unmount command: %s", err) 144 } 145 146 cmd := ShellCommand(unmountCommand) 147 if err := cmd.Run(); err != nil { 148 return fmt.Errorf("Error unmounting root device: %s", err) 149 } 150 151 s.mountPath = "" 152 return nil 153 }