github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/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  	"regexp"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/hashicorp/go-version"
    15  	"github.com/mitchellh/packer/packer"
    16  	"github.com/mitchellh/packer/template/interpolate"
    17  )
    18  
    19  type DockerDriver struct {
    20  	Ui  packer.Ui
    21  	Ctx *interpolate.Context
    22  
    23  	l sync.Mutex
    24  }
    25  
    26  func (d *DockerDriver) DeleteImage(id string) error {
    27  	var stderr bytes.Buffer
    28  	cmd := exec.Command("docker", "rmi", id)
    29  	cmd.Stderr = &stderr
    30  
    31  	log.Printf("Deleting image: %s", id)
    32  	if err := cmd.Start(); err != nil {
    33  		return err
    34  	}
    35  
    36  	if err := cmd.Wait(); err != nil {
    37  		err = fmt.Errorf("Error deleting image: %s\nStderr: %s",
    38  			err, stderr.String())
    39  		return err
    40  	}
    41  
    42  	return nil
    43  }
    44  
    45  func (d *DockerDriver) Commit(id string, author string, changes []string, message string) (string, error) {
    46  	var stdout bytes.Buffer
    47  	var stderr bytes.Buffer
    48  
    49  	args := []string{"commit"}
    50  	if author != "" {
    51  		args = append(args, "--author", author)
    52  	}
    53  	for _, change := range changes {
    54  		args = append(args, "--change", change)
    55  	}
    56  	if message != "" {
    57  		args = append(args, "--message", message)
    58  	}
    59  	args = append(args, id)
    60  
    61  	log.Printf("Committing container with args: %v", args)
    62  	cmd := exec.Command("docker", args...)
    63  	cmd.Stdout = &stdout
    64  	cmd.Stderr = &stderr
    65  
    66  	if err := cmd.Start(); err != nil {
    67  		return "", err
    68  	}
    69  
    70  	if err := cmd.Wait(); err != nil {
    71  		err = fmt.Errorf("Error committing container: %s\nStderr: %s",
    72  			err, stderr.String())
    73  		return "", err
    74  	}
    75  
    76  	return strings.TrimSpace(stdout.String()), nil
    77  }
    78  
    79  func (d *DockerDriver) Export(id string, dst io.Writer) error {
    80  	var stderr bytes.Buffer
    81  	cmd := exec.Command("docker", "export", id)
    82  	cmd.Stdout = dst
    83  	cmd.Stderr = &stderr
    84  
    85  	log.Printf("Exporting container: %s", id)
    86  	if err := cmd.Start(); err != nil {
    87  		return err
    88  	}
    89  
    90  	if err := cmd.Wait(); err != nil {
    91  		err = fmt.Errorf("Error exporting: %s\nStderr: %s",
    92  			err, stderr.String())
    93  		return err
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  func (d *DockerDriver) Import(path string, repo string) (string, error) {
   100  	var stdout bytes.Buffer
   101  	cmd := exec.Command("docker", "import", "-", repo)
   102  	cmd.Stdout = &stdout
   103  	stdin, err := cmd.StdinPipe()
   104  	if err != nil {
   105  		return "", err
   106  	}
   107  
   108  	// There should be only one artifact of the Docker builder
   109  	file, err := os.Open(path)
   110  	if err != nil {
   111  		return "", err
   112  	}
   113  	defer file.Close()
   114  
   115  	if err := cmd.Start(); err != nil {
   116  		return "", err
   117  	}
   118  
   119  	go func() {
   120  		defer stdin.Close()
   121  		io.Copy(stdin, file)
   122  	}()
   123  
   124  	if err := cmd.Wait(); err != nil {
   125  		err = fmt.Errorf("Error importing container: %s", err)
   126  		return "", err
   127  	}
   128  
   129  	return strings.TrimSpace(stdout.String()), nil
   130  }
   131  
   132  func (d *DockerDriver) IPAddress(id string) (string, error) {
   133  	var stderr, stdout bytes.Buffer
   134  	cmd := exec.Command(
   135  		"docker",
   136  		"inspect",
   137  		"--format",
   138  		"{{ .NetworkSettings.IPAddress }}",
   139  		id)
   140  	cmd.Stdout = &stdout
   141  	cmd.Stderr = &stderr
   142  	if err := cmd.Run(); err != nil {
   143  		return "", fmt.Errorf("Error: %s\n\nStderr: %s", err, stderr.String())
   144  	}
   145  
   146  	return strings.TrimSpace(stdout.String()), nil
   147  }
   148  
   149  func (d *DockerDriver) Login(repo, email, user, pass string) error {
   150  	d.l.Lock()
   151  
   152  	args := []string{"login"}
   153  	if email != "" {
   154  		args = append(args, "-e", email)
   155  	}
   156  	if user != "" {
   157  		args = append(args, "-u", user)
   158  	}
   159  	if pass != "" {
   160  		args = append(args, "-p", pass)
   161  	}
   162  	if repo != "" {
   163  		args = append(args, repo)
   164  	}
   165  
   166  	cmd := exec.Command("docker", args...)
   167  	err := runAndStream(cmd, d.Ui)
   168  	if err != nil {
   169  		d.l.Unlock()
   170  	}
   171  
   172  	return err
   173  }
   174  
   175  func (d *DockerDriver) Logout(repo string) error {
   176  	args := []string{"logout"}
   177  	if repo != "" {
   178  		args = append(args, repo)
   179  	}
   180  
   181  	cmd := exec.Command("docker", args...)
   182  	err := runAndStream(cmd, d.Ui)
   183  	d.l.Unlock()
   184  	return err
   185  }
   186  
   187  func (d *DockerDriver) Pull(image string) error {
   188  	cmd := exec.Command("docker", "pull", image)
   189  	return runAndStream(cmd, d.Ui)
   190  }
   191  
   192  func (d *DockerDriver) Push(name string) error {
   193  	cmd := exec.Command("docker", "push", name)
   194  	return runAndStream(cmd, d.Ui)
   195  }
   196  
   197  func (d *DockerDriver) SaveImage(id string, dst io.Writer) error {
   198  	var stderr bytes.Buffer
   199  	cmd := exec.Command("docker", "save", id)
   200  	cmd.Stdout = dst
   201  	cmd.Stderr = &stderr
   202  
   203  	log.Printf("Exporting image: %s", id)
   204  	if err := cmd.Start(); err != nil {
   205  		return err
   206  	}
   207  
   208  	if err := cmd.Wait(); err != nil {
   209  		err = fmt.Errorf("Error exporting: %s\nStderr: %s",
   210  			err, stderr.String())
   211  		return err
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  func (d *DockerDriver) StartContainer(config *ContainerConfig) (string, error) {
   218  	// Build up the template data
   219  	var tplData startContainerTemplate
   220  	tplData.Image = config.Image
   221  	ctx := *d.Ctx
   222  	ctx.Data = &tplData
   223  
   224  	// Args that we're going to pass to Docker
   225  	args := []string{"run"}
   226  	if config.Privileged {
   227  		args = append(args, "--privileged")
   228  	}
   229  	for host, guest := range config.Volumes {
   230  		args = append(args, "-v", fmt.Sprintf("%s:%s", host, guest))
   231  	}
   232  	for _, v := range config.RunCommand {
   233  		v, err := interpolate.Render(v, &ctx)
   234  		if err != nil {
   235  			return "", err
   236  		}
   237  
   238  		args = append(args, v)
   239  	}
   240  	d.Ui.Message(fmt.Sprintf(
   241  		"Run command: docker %s", strings.Join(args, " ")))
   242  
   243  	// Start the container
   244  	var stdout, stderr bytes.Buffer
   245  	cmd := exec.Command("docker", args...)
   246  	cmd.Stdout = &stdout
   247  	cmd.Stderr = &stderr
   248  
   249  	log.Printf("Starting container with args: %v", args)
   250  	if err := cmd.Start(); err != nil {
   251  		return "", err
   252  	}
   253  
   254  	log.Println("Waiting for container to finish starting")
   255  	if err := cmd.Wait(); err != nil {
   256  		if _, ok := err.(*exec.ExitError); ok {
   257  			err = fmt.Errorf("Docker exited with a non-zero exit status.\nStderr: %s",
   258  				stderr.String())
   259  		}
   260  
   261  		return "", err
   262  	}
   263  
   264  	// Capture the container ID, which is alone on stdout
   265  	return strings.TrimSpace(stdout.String()), nil
   266  }
   267  
   268  func (d *DockerDriver) StopContainer(id string) error {
   269  	if err := exec.Command("docker", "kill", id).Run(); err != nil {
   270  		return err
   271  	}
   272  
   273  	return exec.Command("docker", "rm", id).Run()
   274  }
   275  
   276  func (d *DockerDriver) TagImage(id string, repo string, force bool) error {
   277  	args := []string{"tag"}
   278  	if force {
   279  		args = append(args, "-f")
   280  	}
   281  	args = append(args, id, repo)
   282  
   283  	var stderr bytes.Buffer
   284  	cmd := exec.Command("docker", args...)
   285  	cmd.Stderr = &stderr
   286  
   287  	if err := cmd.Start(); err != nil {
   288  		return err
   289  	}
   290  
   291  	if err := cmd.Wait(); err != nil {
   292  		err = fmt.Errorf("Error tagging image: %s\nStderr: %s",
   293  			err, stderr.String())
   294  		return err
   295  	}
   296  
   297  	return nil
   298  }
   299  
   300  func (d *DockerDriver) Verify() error {
   301  	if _, err := exec.LookPath("docker"); err != nil {
   302  		return err
   303  	}
   304  
   305  	return nil
   306  }
   307  
   308  func (d *DockerDriver) Version() (*version.Version, error) {
   309  	output, err := exec.Command("docker", "-v").Output()
   310  	if err != nil {
   311  		return nil, err
   312  	}
   313  
   314  	match := regexp.MustCompile(version.VersionRegexpRaw).FindSubmatch(output)
   315  	if match == nil {
   316  		return nil, fmt.Errorf("unknown version: %s", output)
   317  	}
   318  
   319  	return version.NewVersion(string(match[0]))
   320  }