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