github.com/michael-k/docker@v1.7.0-rc2/integration-cli/docker_cli_by_digest_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os/exec" 6 "regexp" 7 "strings" 8 9 "github.com/docker/docker/utils" 10 "github.com/go-check/check" 11 ) 12 13 var ( 14 repoName = fmt.Sprintf("%v/dockercli/busybox-by-dgst", privateRegistryURL) 15 digestRegex = regexp.MustCompile("Digest: ([^\n]+)") 16 ) 17 18 func setupImage() (string, error) { 19 return setupImageWithTag("latest") 20 } 21 22 func setupImageWithTag(tag string) (string, error) { 23 containerName := "busyboxbydigest" 24 25 cmd := exec.Command(dockerBinary, "run", "-d", "-e", "digest=1", "--name", containerName, "busybox") 26 if _, err := runCommand(cmd); err != nil { 27 return "", err 28 } 29 30 // tag the image to upload it to the private registry 31 repoAndTag := utils.ImageReference(repoName, tag) 32 cmd = exec.Command(dockerBinary, "commit", containerName, repoAndTag) 33 if out, _, err := runCommandWithOutput(cmd); err != nil { 34 return "", fmt.Errorf("image tagging failed: %s, %v", out, err) 35 } 36 37 // delete the container as we don't need it any more 38 if err := deleteContainer(containerName); err != nil { 39 return "", err 40 } 41 42 // push the image 43 cmd = exec.Command(dockerBinary, "push", repoAndTag) 44 out, _, err := runCommandWithOutput(cmd) 45 if err != nil { 46 return "", fmt.Errorf("pushing the image to the private registry has failed: %s, %v", out, err) 47 } 48 49 // delete our local repo that we previously tagged 50 cmd = exec.Command(dockerBinary, "rmi", repoAndTag) 51 if out, _, err := runCommandWithOutput(cmd); err != nil { 52 return "", fmt.Errorf("error deleting images prior to real test: %s, %v", out, err) 53 } 54 55 // the push output includes "Digest: <digest>", so find that 56 matches := digestRegex.FindStringSubmatch(out) 57 if len(matches) != 2 { 58 return "", fmt.Errorf("unable to parse digest from push output: %s", out) 59 } 60 pushDigest := matches[1] 61 62 return pushDigest, nil 63 } 64 65 func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) { 66 pushDigest, err := setupImage() 67 if err != nil { 68 c.Fatalf("error setting up image: %v", err) 69 } 70 71 // pull from the registry using the tag 72 cmd := exec.Command(dockerBinary, "pull", repoName) 73 out, _, err := runCommandWithOutput(cmd) 74 if err != nil { 75 c.Fatalf("error pulling by tag: %s, %v", out, err) 76 } 77 78 // the pull output includes "Digest: <digest>", so find that 79 matches := digestRegex.FindStringSubmatch(out) 80 if len(matches) != 2 { 81 c.Fatalf("unable to parse digest from pull output: %s", out) 82 } 83 pullDigest := matches[1] 84 85 // make sure the pushed and pull digests match 86 if pushDigest != pullDigest { 87 c.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest) 88 } 89 } 90 91 func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) { 92 pushDigest, err := setupImage() 93 if err != nil { 94 c.Fatalf("error setting up image: %v", err) 95 } 96 97 // pull from the registry using the <name>@<digest> reference 98 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 99 cmd := exec.Command(dockerBinary, "pull", imageReference) 100 out, _, err := runCommandWithOutput(cmd) 101 if err != nil { 102 c.Fatalf("error pulling by digest: %s, %v", out, err) 103 } 104 105 // the pull output includes "Digest: <digest>", so find that 106 matches := digestRegex.FindStringSubmatch(out) 107 if len(matches) != 2 { 108 c.Fatalf("unable to parse digest from pull output: %s", out) 109 } 110 pullDigest := matches[1] 111 112 // make sure the pushed and pull digests match 113 if pushDigest != pullDigest { 114 c.Fatalf("push digest %q didn't match pull digest %q", pushDigest, pullDigest) 115 } 116 } 117 118 func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) { 119 // pull from the registry using the <name>@<digest> reference 120 imageReference := fmt.Sprintf("%s@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", repoName) 121 cmd := exec.Command(dockerBinary, "pull", imageReference) 122 out, _, err := runCommandWithOutput(cmd) 123 if err == nil || !strings.Contains(out, "pulling with digest reference failed from v2 registry") { 124 c.Fatalf("expected non-zero exit status and correct error message when pulling non-existing image: %s", out) 125 } 126 } 127 128 func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) { 129 pushDigest, err := setupImage() 130 if err != nil { 131 c.Fatalf("error setting up image: %v", err) 132 } 133 134 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 135 136 containerName := "createByDigest" 137 cmd := exec.Command(dockerBinary, "create", "--name", containerName, imageReference) 138 out, _, err := runCommandWithOutput(cmd) 139 if err != nil { 140 c.Fatalf("error creating by digest: %s, %v", out, err) 141 } 142 143 res, err := inspectField(containerName, "Config.Image") 144 if err != nil { 145 c.Fatalf("failed to get Config.Image: %s, %v", out, err) 146 } 147 if res != imageReference { 148 c.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference) 149 } 150 } 151 152 func (s *DockerRegistrySuite) TestRunByDigest(c *check.C) { 153 pushDigest, err := setupImage() 154 if err != nil { 155 c.Fatalf("error setting up image: %v", err) 156 } 157 158 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 159 160 containerName := "runByDigest" 161 cmd := exec.Command(dockerBinary, "run", "--name", containerName, imageReference, "sh", "-c", "echo found=$digest") 162 out, _, err := runCommandWithOutput(cmd) 163 if err != nil { 164 c.Fatalf("error run by digest: %s, %v", out, err) 165 } 166 167 foundRegex := regexp.MustCompile("found=([^\n]+)") 168 matches := foundRegex.FindStringSubmatch(out) 169 if len(matches) != 2 { 170 c.Fatalf("error locating expected 'found=1' output: %s", out) 171 } 172 if matches[1] != "1" { 173 c.Fatalf("Expected %q, got %q", "1", matches[1]) 174 } 175 176 res, err := inspectField(containerName, "Config.Image") 177 if err != nil { 178 c.Fatalf("failed to get Config.Image: %s, %v", out, err) 179 } 180 if res != imageReference { 181 c.Fatalf("unexpected Config.Image: %s (expected %s)", res, imageReference) 182 } 183 } 184 185 func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) { 186 digest, err := setupImage() 187 if err != nil { 188 c.Fatalf("error setting up image: %v", err) 189 } 190 191 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 192 193 // pull from the registry using the <name>@<digest> reference 194 cmd := exec.Command(dockerBinary, "pull", imageReference) 195 out, _, err := runCommandWithOutput(cmd) 196 if err != nil { 197 c.Fatalf("error pulling by digest: %s, %v", out, err) 198 } 199 200 // make sure inspect runs ok 201 if _, err := inspectField(imageReference, "Id"); err != nil { 202 c.Fatalf("failed to inspect image: %v", err) 203 } 204 205 // do the delete 206 if err := deleteImages(imageReference); err != nil { 207 c.Fatalf("unexpected error deleting image: %v", err) 208 } 209 210 // try to inspect again - it should error this time 211 if _, err := inspectField(imageReference, "Id"); err == nil { 212 c.Fatalf("unexpected nil err trying to inspect what should be a non-existent image") 213 } else if !strings.Contains(err.Error(), "No such image") { 214 c.Fatalf("expected 'No such image' output, got %v", err) 215 } 216 } 217 218 func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) { 219 digest, err := setupImage() 220 if err != nil { 221 c.Fatalf("error setting up image: %v", err) 222 } 223 224 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 225 226 // pull from the registry using the <name>@<digest> reference 227 cmd := exec.Command(dockerBinary, "pull", imageReference) 228 out, _, err := runCommandWithOutput(cmd) 229 if err != nil { 230 c.Fatalf("error pulling by digest: %s, %v", out, err) 231 } 232 233 // get the image id 234 imageID, err := inspectField(imageReference, "Id") 235 if err != nil { 236 c.Fatalf("error getting image id: %v", err) 237 } 238 239 // do the build 240 name := "buildbydigest" 241 _, err = buildImage(name, fmt.Sprintf( 242 `FROM %s 243 CMD ["/bin/echo", "Hello World"]`, imageReference), 244 true) 245 if err != nil { 246 c.Fatal(err) 247 } 248 249 // get the build's image id 250 res, err := inspectField(name, "Config.Image") 251 if err != nil { 252 c.Fatal(err) 253 } 254 // make sure they match 255 if res != imageID { 256 c.Fatalf("Image %s, expected %s", res, imageID) 257 } 258 } 259 260 func (s *DockerRegistrySuite) TestTagByDigest(c *check.C) { 261 digest, err := setupImage() 262 if err != nil { 263 c.Fatalf("error setting up image: %v", err) 264 } 265 266 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 267 268 // pull from the registry using the <name>@<digest> reference 269 cmd := exec.Command(dockerBinary, "pull", imageReference) 270 out, _, err := runCommandWithOutput(cmd) 271 if err != nil { 272 c.Fatalf("error pulling by digest: %s, %v", out, err) 273 } 274 275 // tag it 276 tag := "tagbydigest" 277 cmd = exec.Command(dockerBinary, "tag", imageReference, tag) 278 if _, err := runCommand(cmd); err != nil { 279 c.Fatalf("unexpected error tagging: %v", err) 280 } 281 282 expectedID, err := inspectField(imageReference, "Id") 283 if err != nil { 284 c.Fatalf("error getting original image id: %v", err) 285 } 286 287 tagID, err := inspectField(tag, "Id") 288 if err != nil { 289 c.Fatalf("error getting tagged image id: %v", err) 290 } 291 292 if tagID != expectedID { 293 c.Fatalf("expected image id %q, got %q", expectedID, tagID) 294 } 295 } 296 297 func (s *DockerRegistrySuite) TestListImagesWithoutDigests(c *check.C) { 298 digest, err := setupImage() 299 if err != nil { 300 c.Fatalf("error setting up image: %v", err) 301 } 302 303 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 304 305 // pull from the registry using the <name>@<digest> reference 306 cmd := exec.Command(dockerBinary, "pull", imageReference) 307 out, _, err := runCommandWithOutput(cmd) 308 if err != nil { 309 c.Fatalf("error pulling by digest: %s, %v", out, err) 310 } 311 312 cmd = exec.Command(dockerBinary, "images") 313 out, _, err = runCommandWithOutput(cmd) 314 if err != nil { 315 c.Fatalf("error listing images: %s, %v", out, err) 316 } 317 318 if strings.Contains(out, "DIGEST") { 319 c.Fatalf("list output should not have contained DIGEST header: %s", out) 320 } 321 322 } 323 324 func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) { 325 326 // setup image1 327 digest1, err := setupImageWithTag("tag1") 328 if err != nil { 329 c.Fatalf("error setting up image: %v", err) 330 } 331 imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1) 332 c.Logf("imageReference1 = %s", imageReference1) 333 334 // pull image1 by digest 335 cmd := exec.Command(dockerBinary, "pull", imageReference1) 336 out, _, err := runCommandWithOutput(cmd) 337 if err != nil { 338 c.Fatalf("error pulling by digest: %s, %v", out, err) 339 } 340 341 // list images 342 cmd = exec.Command(dockerBinary, "images", "--digests") 343 out, _, err = runCommandWithOutput(cmd) 344 if err != nil { 345 c.Fatalf("error listing images: %s, %v", out, err) 346 } 347 348 // make sure repo shown, tag=<none>, digest = $digest1 349 re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1 + `\s`) 350 if !re1.MatchString(out) { 351 c.Fatalf("expected %q: %s", re1.String(), out) 352 } 353 354 // setup image2 355 digest2, err := setupImageWithTag("tag2") 356 if err != nil { 357 c.Fatalf("error setting up image: %v", err) 358 } 359 imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2) 360 c.Logf("imageReference2 = %s", imageReference2) 361 362 // pull image1 by digest 363 cmd = exec.Command(dockerBinary, "pull", imageReference1) 364 out, _, err = runCommandWithOutput(cmd) 365 if err != nil { 366 c.Fatalf("error pulling by digest: %s, %v", out, err) 367 } 368 369 // pull image2 by digest 370 cmd = exec.Command(dockerBinary, "pull", imageReference2) 371 out, _, err = runCommandWithOutput(cmd) 372 if err != nil { 373 c.Fatalf("error pulling by digest: %s, %v", out, err) 374 } 375 376 // list images 377 cmd = exec.Command(dockerBinary, "images", "--digests") 378 out, _, err = runCommandWithOutput(cmd) 379 if err != nil { 380 c.Fatalf("error listing images: %s, %v", out, err) 381 } 382 383 // make sure repo shown, tag=<none>, digest = $digest1 384 if !re1.MatchString(out) { 385 c.Fatalf("expected %q: %s", re1.String(), out) 386 } 387 388 // make sure repo shown, tag=<none>, digest = $digest2 389 re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2 + `\s`) 390 if !re2.MatchString(out) { 391 c.Fatalf("expected %q: %s", re2.String(), out) 392 } 393 394 // pull tag1 395 cmd = exec.Command(dockerBinary, "pull", repoName+":tag1") 396 out, _, err = runCommandWithOutput(cmd) 397 if err != nil { 398 c.Fatalf("error pulling tag1: %s, %v", out, err) 399 } 400 401 // list images 402 cmd = exec.Command(dockerBinary, "images", "--digests") 403 out, _, err = runCommandWithOutput(cmd) 404 if err != nil { 405 c.Fatalf("error listing images: %s, %v", out, err) 406 } 407 408 // make sure image 1 has repo, tag, <none> AND repo, <none>, digest 409 reWithTag1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*<none>\s`) 410 reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1 + `\s`) 411 if !reWithTag1.MatchString(out) { 412 c.Fatalf("expected %q: %s", reWithTag1.String(), out) 413 } 414 if !reWithDigest1.MatchString(out) { 415 c.Fatalf("expected %q: %s", reWithDigest1.String(), out) 416 } 417 // make sure image 2 has repo, <none>, digest 418 if !re2.MatchString(out) { 419 c.Fatalf("expected %q: %s", re2.String(), out) 420 } 421 422 // pull tag 2 423 cmd = exec.Command(dockerBinary, "pull", repoName+":tag2") 424 out, _, err = runCommandWithOutput(cmd) 425 if err != nil { 426 c.Fatalf("error pulling tag2: %s, %v", out, err) 427 } 428 429 // list images 430 cmd = exec.Command(dockerBinary, "images", "--digests") 431 out, _, err = runCommandWithOutput(cmd) 432 if err != nil { 433 c.Fatalf("error listing images: %s, %v", out, err) 434 } 435 436 // make sure image 1 has repo, tag, digest 437 if !reWithTag1.MatchString(out) { 438 c.Fatalf("expected %q: %s", re1.String(), out) 439 } 440 441 // make sure image 2 has repo, tag, digest 442 reWithTag2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*<none>\s`) 443 reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2 + `\s`) 444 if !reWithTag2.MatchString(out) { 445 c.Fatalf("expected %q: %s", reWithTag2.String(), out) 446 } 447 if !reWithDigest2.MatchString(out) { 448 c.Fatalf("expected %q: %s", reWithDigest2.String(), out) 449 } 450 451 // list images 452 cmd = exec.Command(dockerBinary, "images", "--digests") 453 out, _, err = runCommandWithOutput(cmd) 454 if err != nil { 455 c.Fatalf("error listing images: %s, %v", out, err) 456 } 457 458 // make sure image 1 has repo, tag, digest 459 if !reWithTag1.MatchString(out) { 460 c.Fatalf("expected %q: %s", re1.String(), out) 461 } 462 // make sure image 2 has repo, tag, digest 463 if !reWithTag2.MatchString(out) { 464 c.Fatalf("expected %q: %s", re2.String(), out) 465 } 466 // make sure busybox has tag, but not digest 467 busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*<none>\s`) 468 if !busyboxRe.MatchString(out) { 469 c.Fatalf("expected %q: %s", busyboxRe.String(), out) 470 } 471 } 472 473 func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C) { 474 pushDigest, err := setupImage() 475 if err != nil { 476 c.Fatalf("error setting up image: %v", err) 477 } 478 479 // pull from the registry using the <name>@<digest> reference 480 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 481 cmd := exec.Command(dockerBinary, "pull", imageReference) 482 out, _, err := runCommandWithOutput(cmd) 483 if err != nil { 484 c.Fatalf("error pulling by digest: %s, %v", out, err) 485 } 486 // just in case... 487 488 imageID, err := inspectField(imageReference, ".Id") 489 if err != nil { 490 c.Fatalf("error inspecting image id: %v", err) 491 } 492 493 cmd = exec.Command(dockerBinary, "rmi", imageID) 494 if _, err := runCommand(cmd); err != nil { 495 c.Fatalf("error deleting image by id: %v", err) 496 } 497 }