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