forked from hashicorp/packer
/
driver_docker.go
161 lines (132 loc) · 3.41 KB
/
driver_docker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package docker
import (
"bytes"
"fmt"
"github.com/mitchellh/packer/packer"
"io"
"log"
"os"
"os/exec"
"strings"
)
type DockerDriver struct {
Ui packer.Ui
Tpl *packer.ConfigTemplate
}
func (d *DockerDriver) DeleteImage(id string) error {
var stderr bytes.Buffer
cmd := exec.Command("docker", "rmi", id)
cmd.Stderr = &stderr
log.Printf("Deleting image: %s", id)
if err := cmd.Start(); err != nil {
return err
}
if err := cmd.Wait(); err != nil {
err = fmt.Errorf("Error deleting image: %s\nStderr: %s",
err, stderr.String())
return err
}
return nil
}
func (d *DockerDriver) Export(id string, dst io.Writer) error {
var stderr bytes.Buffer
cmd := exec.Command("docker", "export", id)
cmd.Stdout = dst
cmd.Stderr = &stderr
log.Printf("Exporting container: %s", id)
if err := cmd.Start(); err != nil {
return err
}
if err := cmd.Wait(); err != nil {
err = fmt.Errorf("Error exporting: %s\nStderr: %s",
err, stderr.String())
return err
}
return nil
}
func (d *DockerDriver) Import(path string, repo string) (string, error) {
var stdout bytes.Buffer
cmd := exec.Command("docker", "import", "-", repo)
cmd.Stdout = &stdout
stdin, err := cmd.StdinPipe()
if err != nil {
return "", err
}
// There should be only one artifact of the Docker builder
file, err := os.Open(path)
if err != nil {
return "", err
}
defer file.Close()
if err := cmd.Start(); err != nil {
return "", err
}
go func() {
defer stdin.Close()
io.Copy(stdin, file)
}()
if err := cmd.Wait(); err != nil {
err = fmt.Errorf("Error importing container: %s", err)
return "", err
}
return strings.TrimSpace(stdout.String()), nil
}
func (d *DockerDriver) Pull(image string) error {
cmd := exec.Command("docker", "pull", image)
return runAndStream(cmd, d.Ui)
}
func (d *DockerDriver) Push(name string) error {
cmd := exec.Command("docker", "push", name)
return runAndStream(cmd, d.Ui)
}
func (d *DockerDriver) StartContainer(config *ContainerConfig) (string, error) {
// Build up the template data
var tplData startContainerTemplate
tplData.Image = config.Image
if len(config.Volumes) > 0 {
volumes := make([]string, 0, len(config.Volumes))
for host, guest := range config.Volumes {
volumes = append(volumes, fmt.Sprintf("%s:%s", host, guest))
}
tplData.Volumes = strings.Join(volumes, ",")
}
// Args that we're going to pass to Docker
args := config.RunCommand
for i, v := range args {
var err error
args[i], err = d.Tpl.Process(v, &tplData)
if err != nil {
return "", err
}
}
d.Ui.Message(fmt.Sprintf(
"Run command: docker %s", strings.Join(args, " ")))
// Start the container
var stdout, stderr bytes.Buffer
cmd := exec.Command("docker", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
log.Printf("Starting container with args: %v", args)
if err := cmd.Start(); err != nil {
return "", err
}
log.Println("Waiting for container to finish starting")
if err := cmd.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); ok {
err = fmt.Errorf("Docker exited with a non-zero exit status.\nStderr: %s",
stderr.String())
}
return "", err
}
// Capture the container ID, which is alone on stdout
return strings.TrimSpace(stdout.String()), nil
}
func (d *DockerDriver) StopContainer(id string) error {
return exec.Command("docker", "kill", id).Run()
}
func (d *DockerDriver) Verify() error {
if _, err := exec.LookPath("docker"); err != nil {
return err
}
return nil
}