github.com/sneal/packer@v0.5.2/builder/amazon/chroot/communicator.go (about) 1 package chroot 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/mitchellh/packer/packer" 7 "io" 8 "io/ioutil" 9 "log" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "strings" 14 "syscall" 15 ) 16 17 // Communicator is a special communicator that works by executing 18 // commands locally but within a chroot. 19 type Communicator struct { 20 Chroot string 21 CmdWrapper CommandWrapper 22 } 23 24 func (c *Communicator) Start(cmd *packer.RemoteCmd) error { 25 command, err := c.CmdWrapper( 26 fmt.Sprintf("chroot %s /bin/sh -c \"%s\"", c.Chroot, cmd.Command)) 27 if err != nil { 28 return err 29 } 30 31 localCmd := ShellCommand(command) 32 localCmd.Stdin = cmd.Stdin 33 localCmd.Stdout = cmd.Stdout 34 localCmd.Stderr = cmd.Stderr 35 log.Printf("Executing: %s %#v", localCmd.Path, localCmd.Args) 36 if err := localCmd.Start(); err != nil { 37 return err 38 } 39 40 go func() { 41 exitStatus := 0 42 if err := localCmd.Wait(); err != nil { 43 if exitErr, ok := err.(*exec.ExitError); ok { 44 exitStatus = 1 45 46 // There is no process-independent way to get the REAL 47 // exit status so we just try to go deeper. 48 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { 49 exitStatus = status.ExitStatus() 50 } 51 } 52 } 53 54 log.Printf( 55 "Chroot execution exited with '%d': '%s'", 56 exitStatus, cmd.Command) 57 cmd.SetExited(exitStatus) 58 }() 59 60 return nil 61 } 62 63 func (c *Communicator) Upload(dst string, r io.Reader) error { 64 dst = filepath.Join(c.Chroot, dst) 65 log.Printf("Uploading to chroot dir: %s", dst) 66 tf, err := ioutil.TempFile("", "packer-amazon-chroot") 67 if err != nil { 68 return fmt.Errorf("Error preparing shell script: %s", err) 69 } 70 defer os.Remove(tf.Name()) 71 io.Copy(tf, r) 72 73 cpCmd, err := c.CmdWrapper(fmt.Sprintf("cp %s %s", tf.Name(), dst)) 74 if err != nil { 75 return err 76 } 77 78 return ShellCommand(cpCmd).Run() 79 } 80 81 func (c *Communicator) UploadDir(dst string, src string, exclude []string) error { 82 // TODO: remove any file copied if it appears in `exclude` 83 chrootDest := filepath.Join(c.Chroot, dst) 84 log.Printf("Uploading directory '%s' to '%s'", src, chrootDest) 85 cpCmd, err := c.CmdWrapper(fmt.Sprintf("cp -R %s* %s", src, chrootDest)) 86 if err != nil { 87 return err 88 } 89 90 var stderr bytes.Buffer 91 cmd := ShellCommand(cpCmd) 92 cmd.Env = append(cmd.Env, os.Environ()...) 93 cmd.Env = append(cmd.Env, "LANG=C") 94 cmd.Stderr = &stderr 95 err = cmd.Run() 96 if err == nil { 97 return err 98 } 99 100 if strings.Contains(stderr.String(), "No such file") { 101 // This just means that the directory was empty. Just ignore it. 102 return nil 103 } 104 105 return err 106 } 107 108 func (c *Communicator) Download(src string, w io.Writer) error { 109 src = filepath.Join(c.Chroot, src) 110 log.Printf("Downloading from chroot dir: %s", src) 111 f, err := os.Open(src) 112 if err != nil { 113 return err 114 } 115 defer f.Close() 116 117 if _, err := io.Copy(w, f); err != nil { 118 return err 119 } 120 121 return nil 122 }