github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/lxc/communicator.go (about) 1 package lxc 2 3 import ( 4 "fmt" 5 "github.com/hashicorp/packer/packer" 6 "io" 7 "io/ioutil" 8 "log" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strings" 13 "syscall" 14 ) 15 16 type LxcAttachCommunicator struct { 17 RootFs string 18 ContainerName string 19 CmdWrapper CommandWrapper 20 } 21 22 func (c *LxcAttachCommunicator) Start(cmd *packer.RemoteCmd) error { 23 localCmd, err := c.Execute(cmd.Command) 24 25 if err != nil { 26 return err 27 } 28 29 localCmd.Stdin = cmd.Stdin 30 localCmd.Stdout = cmd.Stdout 31 localCmd.Stderr = cmd.Stderr 32 if err := localCmd.Start(); err != nil { 33 return err 34 } 35 36 go func() { 37 exitStatus := 0 38 if err := localCmd.Wait(); err != nil { 39 if exitErr, ok := err.(*exec.ExitError); ok { 40 exitStatus = 1 41 42 // There is no process-independent way to get the REAL 43 // exit status so we just try to go deeper. 44 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { 45 exitStatus = status.ExitStatus() 46 } 47 } 48 } 49 50 log.Printf( 51 "lxc-attach execution exited with '%d': '%s'", 52 exitStatus, cmd.Command) 53 cmd.SetExited(exitStatus) 54 }() 55 56 return nil 57 } 58 59 func (c *LxcAttachCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error { 60 dst = filepath.Join(c.RootFs, dst) 61 log.Printf("Uploading to rootfs: %s", dst) 62 tf, err := ioutil.TempFile("", "packer-lxc-attach") 63 if err != nil { 64 return fmt.Errorf("Error uploading file to rootfs: %s", err) 65 } 66 defer os.Remove(tf.Name()) 67 io.Copy(tf, r) 68 69 cpCmd, err := c.CmdWrapper(fmt.Sprintf("sudo cp %s %s", tf.Name(), dst)) 70 if err != nil { 71 return err 72 } 73 74 log.Printf("Running copy command: %s", dst) 75 76 return ShellCommand(cpCmd).Run() 77 } 78 79 func (c *LxcAttachCommunicator) UploadDir(dst string, src string, exclude []string) error { 80 // TODO: remove any file copied if it appears in `exclude` 81 dest := filepath.Join(c.RootFs, dst) 82 log.Printf("Uploading directory '%s' to rootfs '%s'", src, dest) 83 cpCmd, err := c.CmdWrapper(fmt.Sprintf("sudo cp -R %s/. %s", src, dest)) 84 if err != nil { 85 return err 86 } 87 88 return ShellCommand(cpCmd).Run() 89 } 90 91 func (c *LxcAttachCommunicator) Download(src string, w io.Writer) error { 92 src = filepath.Join(c.RootFs, src) 93 log.Printf("Downloading from rootfs dir: %s", src) 94 f, err := os.Open(src) 95 if err != nil { 96 return err 97 } 98 defer f.Close() 99 100 if _, err := io.Copy(w, f); err != nil { 101 return err 102 } 103 104 return nil 105 } 106 107 func (c *LxcAttachCommunicator) DownloadDir(src string, dst string, exclude []string) error { 108 return fmt.Errorf("DownloadDir is not implemented for lxc") 109 } 110 111 func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) { 112 log.Printf("Executing with lxc-attach in container: %s %s %s", c.ContainerName, c.RootFs, commandString) 113 command, err := c.CmdWrapper( 114 fmt.Sprintf("sudo lxc-attach --name %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString)) 115 if err != nil { 116 return nil, err 117 } 118 119 localCmd := ShellCommand(command) 120 log.Printf("Executing lxc-attach: %s %#v", localCmd.Path, localCmd.Args) 121 122 return localCmd, nil 123 } 124 125 func (c *LxcAttachCommunicator) CheckInit() (string, error) { 126 log.Printf("Debug runlevel exec") 127 localCmd, err := c.Execute("/sbin/runlevel") 128 129 if err != nil { 130 return "", err 131 } 132 133 pr, _ := localCmd.StdoutPipe() 134 if err = localCmd.Start(); err != nil { 135 return "", err 136 } 137 138 output, err := ioutil.ReadAll(pr) 139 140 if err != nil { 141 return "", err 142 } 143 144 err = localCmd.Wait() 145 146 if err != nil { 147 return "", err 148 } 149 150 return strings.TrimSpace(string(output)), nil 151 }