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