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 }