github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/docker/driver_docker.go (about)

     1  package docker
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"os/exec"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/mitchellh/packer/packer"
    14  )
    15  
    16  type DockerDriver struct {
    17  	Ui  packer.Ui
    18  	Tpl *packer.ConfigTemplate
    19  
    20  	l sync.Mutex
    21  }
    22  
    23  func (d *DockerDriver) DeleteImage(id string) error {
    24  	var stderr bytes.Buffer
    25  	cmd := exec.Command("docker", "rmi", id)
    26  	cmd.Stderr = &stderr
    27  
    28  	log.Printf("Deleting image: %s", id)
    29  	if err := cmd.Start(); err != nil {
    30  		return err
    31  	}
    32  
    33  	if err := cmd.Wait(); err != nil {
    34  		err = fmt.Errorf("Error deleting image: %s\nStderr: %s",
    35  			err, stderr.String())
    36  		return err
    37  	}
    38  
    39  	return nil
    40  }
    41  
    42  func (d *DockerDriver) Commit(id string) (string, error) {
    43  	var stdout bytes.Buffer
    44  	var stderr bytes.Buffer
    45  
    46  	cmd := exec.Command("docker", "commit", id)
    47  	cmd.Stdout = &stdout
    48  	cmd.Stderr = &stderr
    49  
    50  	if err := cmd.Start(); err != nil {
    51  		return "", err
    52  	}
    53  
    54  	if err := cmd.Wait(); err != nil {
    55  		err = fmt.Errorf("Error committing container: %s\nStderr: %s",
    56  			err, stderr.String())
    57  		return "", err
    58  	}
    59  
    60  	return strings.TrimSpace(stdout.String()), nil
    61  }
    62  
    63  func (d *DockerDriver) Export(id string, dst io.Writer) error {
    64  	var stderr bytes.Buffer
    65  	cmd := exec.Command("docker", "export", id)
    66  	cmd.Stdout = dst
    67  	cmd.Stderr = &stderr
    68  
    69  	log.Printf("Exporting container: %s", id)
    70  	if err := cmd.Start(); err != nil {
    71  		return err
    72  	}
    73  
    74  	if err := cmd.Wait(); err != nil {
    75  		err = fmt.Errorf("Error exporting: %s\nStderr: %s",
    76  			err, stderr.String())
    77  		return err
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func (d *DockerDriver) Import(path string, repo string) (string, error) {
    84  	var stdout bytes.Buffer
    85  	cmd := exec.Command("docker", "import", "-", repo)
    86  	cmd.Stdout = &stdout
    87  	stdin, err := cmd.StdinPipe()
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  
    92  	// There should be only one artifact of the Docker builder
    93  	file, err := os.Open(path)
    94  	if err != nil {
    95  		return "", err
    96  	}
    97  	defer file.Close()
    98  
    99  	if err := cmd.Start(); err != nil {
   100  		return "", err
   101  	}
   102  
   103  	go func() {
   104  		defer stdin.Close()
   105  		io.Copy(stdin, file)
   106  	}()
   107  
   108  	if err := cmd.Wait(); err != nil {
   109  		err = fmt.Errorf("Error importing container: %s", err)
   110  		return "", err
   111  	}
   112  
   113  	return strings.TrimSpace(stdout.String()), nil
   114  }
   115  
   116  func (d *DockerDriver) Login(repo, email, user, pass string) error {
   117  	d.l.Lock()
   118  
   119  	args := []string{"login"}
   120  	if email != "" {
   121  		args = append(args, "-e", email)
   122  	}
   123  	if user != "" {
   124  		args = append(args, "-u", user)
   125  	}
   126  	if pass != "" {
   127  		args = append(args, "-p", pass)
   128  	}
   129  	if repo != "" {
   130  		args = append(args, repo)
   131  	}
   132  
   133  	cmd := exec.Command("docker", args...)
   134  	err := runAndStream(cmd, d.Ui)
   135  	if err != nil {
   136  		d.l.Unlock()
   137  	}
   138  
   139  	return err
   140  }
   141  
   142  func (d *DockerDriver) Logout(repo string) error {
   143  	args := []string{"logout"}
   144  	if repo != "" {
   145  		args = append(args, repo)
   146  	}
   147  
   148  	cmd := exec.Command("docker", args...)
   149  	err := runAndStream(cmd, d.Ui)
   150  	d.l.Unlock()
   151  	return err
   152  }
   153  
   154  func (d *DockerDriver) Pull(image string) error {
   155  	cmd := exec.Command("docker", "pull", image)
   156  	return runAndStream(cmd, d.Ui)
   157  }
   158  
   159  func (d *DockerDriver) Push(name string) error {
   160  	cmd := exec.Command("docker", "push", name)
   161  	return runAndStream(cmd, d.Ui)
   162  }
   163  
   164  func (d *DockerDriver) SaveImage(id string, dst io.Writer) error {
   165  	var stderr bytes.Buffer
   166  	cmd := exec.Command("docker", "save", id)
   167  	cmd.Stdout = dst
   168  	cmd.Stderr = &stderr
   169  
   170  	log.Printf("Exporting image: %s", id)
   171  	if err := cmd.Start(); err != nil {
   172  		return err
   173  	}
   174  
   175  	if err := cmd.Wait(); err != nil {
   176  		err = fmt.Errorf("Error exporting: %s\nStderr: %s",
   177  			err, stderr.String())
   178  		return err
   179  	}
   180  
   181  	return nil
   182  }
   183  
   184  func (d *DockerDriver) StartContainer(config *ContainerConfig) (string, error) {
   185  	// Build up the template data
   186  	var tplData startContainerTemplate
   187  	tplData.Image = config.Image
   188  
   189  	// Args that we're going to pass to Docker
   190  	args := []string{"run"}
   191  	for host, guest := range config.Volumes {
   192  		args = append(args, "-v", fmt.Sprintf("%s:%s", host, guest))
   193  	}
   194  	for _, v := range config.RunCommand {
   195  		v, err := d.Tpl.Process(v, &tplData)
   196  		if err != nil {
   197  			return "", err
   198  		}
   199  
   200  		args = append(args, v)
   201  	}
   202  	d.Ui.Message(fmt.Sprintf(
   203  		"Run command: docker %s", strings.Join(args, " ")))
   204  
   205  	// Start the container
   206  	var stdout, stderr bytes.Buffer
   207  	cmd := exec.Command("docker", args...)
   208  	cmd.Stdout = &stdout
   209  	cmd.Stderr = &stderr
   210  
   211  	log.Printf("Starting container with args: %v", args)
   212  	if err := cmd.Start(); err != nil {
   213  		return "", err
   214  	}
   215  
   216  	log.Println("Waiting for container to finish starting")
   217  	if err := cmd.Wait(); err != nil {
   218  		if _, ok := err.(*exec.ExitError); ok {
   219  			err = fmt.Errorf("Docker exited with a non-zero exit status.\nStderr: %s",
   220  				stderr.String())
   221  		}
   222  
   223  		return "", err
   224  	}
   225  
   226  	// Capture the container ID, which is alone on stdout
   227  	return strings.TrimSpace(stdout.String()), nil
   228  }
   229  
   230  func (d *DockerDriver) StopContainer(id string) error {
   231  	if err := exec.Command("docker", "kill", id).Run(); err != nil {
   232  		return err
   233  	}
   234  
   235  	return exec.Command("docker", "rm", id).Run()
   236  }
   237  
   238  func (d *DockerDriver) TagImage(id string, repo string) error {
   239  	var stderr bytes.Buffer
   240  	cmd := exec.Command("docker", "tag", id, repo)
   241  	cmd.Stderr = &stderr
   242  
   243  	if err := cmd.Start(); err != nil {
   244  		return err
   245  	}
   246  
   247  	if err := cmd.Wait(); err != nil {
   248  		err = fmt.Errorf("Error tagging image: %s\nStderr: %s",
   249  			err, stderr.String())
   250  		return err
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  func (d *DockerDriver) Verify() error {
   257  	if _, err := exec.LookPath("docker"); err != nil {
   258  		return err
   259  	}
   260  
   261  	if v := os.Getenv("DOCKER_HOST"); v != "" {
   262  		return fmt.Errorf(
   263  			"DOCKER_HOST cannot be set with the Packer Docker builder.")
   264  	}
   265  
   266  	return nil
   267  }