github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/chroot/step_mount_extra.go (about) 1 package chroot 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "os" 8 "os/exec" 9 "syscall" 10 11 "github.com/hashicorp/packer/helper/multistep" 12 "github.com/hashicorp/packer/packer" 13 ) 14 15 // StepMountExtra mounts the attached device. 16 // 17 // Produces: 18 // mount_extra_cleanup CleanupFunc - To perform early cleanup 19 type StepMountExtra struct { 20 mounts []string 21 } 22 23 func (s *StepMountExtra) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 24 config := state.Get("config").(*Config) 25 mountPath := state.Get("mount_path").(string) 26 ui := state.Get("ui").(packer.Ui) 27 wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) 28 29 s.mounts = make([]string, 0, len(config.ChrootMounts)) 30 31 ui.Say("Mounting additional paths within the chroot...") 32 for _, mountInfo := range config.ChrootMounts { 33 innerPath := mountPath + mountInfo[2] 34 35 if err := os.MkdirAll(innerPath, 0755); err != nil { 36 err := fmt.Errorf("Error creating mount directory: %s", err) 37 state.Put("error", err) 38 ui.Error(err.Error()) 39 return multistep.ActionHalt 40 } 41 42 flags := "-t " + mountInfo[0] 43 if mountInfo[0] == "bind" { 44 flags = "--bind" 45 } 46 47 ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2])) 48 stderr := new(bytes.Buffer) 49 mountCommand, err := wrappedCommand(fmt.Sprintf( 50 "mount %s %s %s", 51 flags, 52 mountInfo[1], 53 innerPath)) 54 if err != nil { 55 err := fmt.Errorf("Error creating mount command: %s", err) 56 state.Put("error", err) 57 ui.Error(err.Error()) 58 return multistep.ActionHalt 59 } 60 61 cmd := ShellCommand(mountCommand) 62 cmd.Stderr = stderr 63 if err := cmd.Run(); err != nil { 64 err := fmt.Errorf( 65 "Error mounting: %s\nStderr: %s", err, stderr.String()) 66 state.Put("error", err) 67 ui.Error(err.Error()) 68 return multistep.ActionHalt 69 } 70 71 s.mounts = append(s.mounts, innerPath) 72 } 73 74 state.Put("mount_extra_cleanup", s) 75 return multistep.ActionContinue 76 } 77 78 func (s *StepMountExtra) Cleanup(state multistep.StateBag) { 79 ui := state.Get("ui").(packer.Ui) 80 81 if err := s.CleanupFunc(state); err != nil { 82 ui.Error(err.Error()) 83 return 84 } 85 } 86 87 func (s *StepMountExtra) CleanupFunc(state multistep.StateBag) error { 88 if s.mounts == nil { 89 return nil 90 } 91 92 wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) 93 for len(s.mounts) > 0 { 94 var path string 95 lastIndex := len(s.mounts) - 1 96 path, s.mounts = s.mounts[lastIndex], s.mounts[:lastIndex] 97 98 grepCommand, err := wrappedCommand(fmt.Sprintf("grep %s /proc/mounts", path)) 99 if err != nil { 100 return fmt.Errorf("Error creating grep command: %s", err) 101 } 102 103 // Before attempting to unmount, 104 // check to see if path is already unmounted 105 stderr := new(bytes.Buffer) 106 cmd := ShellCommand(grepCommand) 107 cmd.Stderr = stderr 108 if err := cmd.Run(); err != nil { 109 if exitError, ok := err.(*exec.ExitError); ok { 110 if status, ok := exitError.Sys().(syscall.WaitStatus); ok { 111 exitStatus := status.ExitStatus() 112 if exitStatus == 1 { 113 // path has already been unmounted 114 // just skip this path 115 continue 116 } 117 } 118 } 119 } 120 121 unmountCommand, err := wrappedCommand(fmt.Sprintf("umount %s", path)) 122 if err != nil { 123 return fmt.Errorf("Error creating unmount command: %s", err) 124 } 125 126 stderr = new(bytes.Buffer) 127 cmd = ShellCommand(unmountCommand) 128 cmd.Stderr = stderr 129 if err := cmd.Run(); err != nil { 130 return fmt.Errorf( 131 "Error unmounting device: %s\nStderr: %s", err, stderr.String()) 132 } 133 } 134 135 s.mounts = nil 136 return nil 137 }