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 }