github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/lxd/communicator.go (about)

     1  package lxd
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/hashicorp/packer/packer"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"syscall"
    12  )
    13  
    14  type Communicator struct {
    15  	ContainerName string
    16  	CmdWrapper    CommandWrapper
    17  }
    18  
    19  func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
    20  	localCmd, err := c.Execute(cmd.Command)
    21  
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	localCmd.Stdin = cmd.Stdin
    27  	localCmd.Stdout = cmd.Stdout
    28  	localCmd.Stderr = cmd.Stderr
    29  	if err := localCmd.Start(); err != nil {
    30  		return err
    31  	}
    32  
    33  	go func() {
    34  		exitStatus := 0
    35  		if err := localCmd.Wait(); err != nil {
    36  			if exitErr, ok := err.(*exec.ExitError); ok {
    37  				exitStatus = 1
    38  
    39  				// There is no process-independent way to get the REAL
    40  				// exit status so we just try to go deeper.
    41  				if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
    42  					exitStatus = status.ExitStatus()
    43  				}
    44  			}
    45  		}
    46  
    47  		log.Printf(
    48  			"lxc exec execution exited with '%d': '%s'",
    49  			exitStatus, cmd.Command)
    50  		cmd.SetExited(exitStatus)
    51  	}()
    52  
    53  	return nil
    54  }
    55  
    56  func (c *Communicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error {
    57  	cpCmd, err := c.CmdWrapper(fmt.Sprintf("lxc file push - %s", filepath.Join(c.ContainerName, dst)))
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	log.Printf("Running copy command: %s", cpCmd)
    63  	command := ShellCommand(cpCmd)
    64  	command.Stdin = r
    65  
    66  	return command.Run()
    67  }
    68  
    69  func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
    70  	// NOTE:lxc file push doesn't yet support directory uploads.
    71  	// As a work around, we tar up the folder, upload it as a file, then extract it
    72  
    73  	// Don't use 'z' flag as compressing may take longer and the transfer is likely local.
    74  	// If this isn't the case, it is possible for the user to compress in another step then transfer.
    75  	// It wouldn't be possibe to disable compression, without exposing this option.
    76  	tar, err := c.CmdWrapper(fmt.Sprintf("tar -cf - -C %s .", src))
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	cp, err := c.CmdWrapper(fmt.Sprintf("lxc exec %s -- tar -xf - -C %s", c.ContainerName, dst))
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	tarCmd := ShellCommand(tar)
    87  	cpCmd := ShellCommand(cp)
    88  
    89  	cpCmd.Stdin, _ = tarCmd.StdoutPipe()
    90  	log.Printf("Starting tar command: %s", tar)
    91  	err = tarCmd.Start()
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	log.Printf("Running cp command: %s", cp)
    97  	err = cpCmd.Run()
    98  	if err != nil {
    99  		log.Printf("Error running cp command: %s", err)
   100  		return err
   101  	}
   102  
   103  	err = tarCmd.Wait()
   104  	if err != nil {
   105  		log.Printf("Error running tar command: %s", err)
   106  		return err
   107  	}
   108  
   109  	return nil
   110  }
   111  
   112  func (c *Communicator) Download(src string, w io.Writer) error {
   113  	cpCmd, err := c.CmdWrapper(fmt.Sprintf("lxc file pull %s -", filepath.Join(c.ContainerName, src)))
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	log.Printf("Running copy command: %s", cpCmd)
   119  	command := ShellCommand(cpCmd)
   120  	command.Stdout = w
   121  
   122  	return command.Run()
   123  }
   124  
   125  func (c *Communicator) DownloadDir(src string, dst string, exclude []string) error {
   126  	// TODO This could probably be "lxc exec <container> -- cd <src> && tar -czf - | tar -xzf - -C <dst>"
   127  	return fmt.Errorf("DownloadDir is not implemented for lxc")
   128  }
   129  
   130  func (c *Communicator) Execute(commandString string) (*exec.Cmd, error) {
   131  	log.Printf("Executing with lxc exec in container: %s %s", c.ContainerName, commandString)
   132  	command, err := c.CmdWrapper(
   133  		fmt.Sprintf("lxc exec %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString))
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	localCmd := ShellCommand(command)
   139  	log.Printf("Executing lxc exec: %s %#v", localCmd.Path, localCmd.Args)
   140  
   141  	return localCmd, nil
   142  }