The test injects a synthetic manifest list into the registry blob store,
since there isn't a tool for pushing them yet.
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
| ... | ... |
@@ -1,10 +1,20 @@ |
| 1 | 1 |
package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/json" |
|
| 4 | 5 |
"fmt" |
| 6 |
+ "io/ioutil" |
|
| 7 |
+ "os" |
|
| 5 | 8 |
"os/exec" |
| 9 |
+ "path/filepath" |
|
| 10 |
+ "runtime" |
|
| 6 | 11 |
"strings" |
| 7 | 12 |
|
| 13 |
+ "github.com/docker/distribution" |
|
| 14 |
+ "github.com/docker/distribution/digest" |
|
| 15 |
+ "github.com/docker/distribution/manifest" |
|
| 16 |
+ "github.com/docker/distribution/manifest/manifestlist" |
|
| 17 |
+ "github.com/docker/distribution/manifest/schema2" |
|
| 8 | 18 |
"github.com/docker/docker/pkg/integration/checker" |
| 9 | 19 |
"github.com/go-check/check" |
| 10 | 20 |
) |
| ... | ... |
@@ -280,3 +290,85 @@ func (s *DockerRegistrySuite) TestPullFallbackOn404(c *check.C) {
|
| 280 | 280 |
|
| 281 | 281 |
c.Assert(out, checker.Contains, "v1 ping attempt") |
| 282 | 282 |
} |
| 283 |
+ |
|
| 284 |
+func (s *DockerRegistrySuite) TestPullManifestList(c *check.C) {
|
|
| 285 |
+ pushDigest, err := setupImage(c) |
|
| 286 |
+ c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
|
|
| 287 |
+ |
|
| 288 |
+ // Inject a manifest list into the registry |
|
| 289 |
+ manifestList := &manifestlist.ManifestList{
|
|
| 290 |
+ Versioned: manifest.Versioned{
|
|
| 291 |
+ SchemaVersion: 2, |
|
| 292 |
+ MediaType: manifestlist.MediaTypeManifestList, |
|
| 293 |
+ }, |
|
| 294 |
+ Manifests: []manifestlist.ManifestDescriptor{
|
|
| 295 |
+ {
|
|
| 296 |
+ Descriptor: distribution.Descriptor{
|
|
| 297 |
+ Digest: "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b", |
|
| 298 |
+ Size: 3253, |
|
| 299 |
+ MediaType: schema2.MediaTypeManifest, |
|
| 300 |
+ }, |
|
| 301 |
+ Platform: manifestlist.PlatformSpec{
|
|
| 302 |
+ Architecture: "bogus_arch", |
|
| 303 |
+ OS: "bogus_os", |
|
| 304 |
+ }, |
|
| 305 |
+ }, |
|
| 306 |
+ {
|
|
| 307 |
+ Descriptor: distribution.Descriptor{
|
|
| 308 |
+ Digest: pushDigest, |
|
| 309 |
+ Size: 3253, |
|
| 310 |
+ MediaType: schema2.MediaTypeManifest, |
|
| 311 |
+ }, |
|
| 312 |
+ Platform: manifestlist.PlatformSpec{
|
|
| 313 |
+ Architecture: runtime.GOARCH, |
|
| 314 |
+ OS: runtime.GOOS, |
|
| 315 |
+ }, |
|
| 316 |
+ }, |
|
| 317 |
+ }, |
|
| 318 |
+ } |
|
| 319 |
+ |
|
| 320 |
+ manifestListJSON, err := json.MarshalIndent(manifestList, "", " ") |
|
| 321 |
+ c.Assert(err, checker.IsNil, check.Commentf("error marshalling manifest list"))
|
|
| 322 |
+ |
|
| 323 |
+ manifestListDigest := digest.FromBytes(manifestListJSON) |
|
| 324 |
+ hexDigest := manifestListDigest.Hex() |
|
| 325 |
+ |
|
| 326 |
+ registryV2Path := filepath.Join(s.reg.dir, "docker", "registry", "v2") |
|
| 327 |
+ |
|
| 328 |
+ // Write manifest list to blob store |
|
| 329 |
+ blobDir := filepath.Join(registryV2Path, "blobs", "sha256", hexDigest[:2], hexDigest) |
|
| 330 |
+ err = os.MkdirAll(blobDir, 0755) |
|
| 331 |
+ c.Assert(err, checker.IsNil, check.Commentf("error creating blob dir"))
|
|
| 332 |
+ blobPath := filepath.Join(blobDir, "data") |
|
| 333 |
+ err = ioutil.WriteFile(blobPath, []byte(manifestListJSON), 0644) |
|
| 334 |
+ c.Assert(err, checker.IsNil, check.Commentf("error writing manifest list"))
|
|
| 335 |
+ |
|
| 336 |
+ // Add to revision store |
|
| 337 |
+ revisionDir := filepath.Join(registryV2Path, "repositories", remoteRepoName, "_manifests", "revisions", "sha256", hexDigest) |
|
| 338 |
+ err = os.Mkdir(revisionDir, 0755) |
|
| 339 |
+ c.Assert(err, checker.IsNil, check.Commentf("error creating revision dir"))
|
|
| 340 |
+ revisionPath := filepath.Join(revisionDir, "link") |
|
| 341 |
+ err = ioutil.WriteFile(revisionPath, []byte(manifestListDigest.String()), 0644) |
|
| 342 |
+ c.Assert(err, checker.IsNil, check.Commentf("error writing revision link"))
|
|
| 343 |
+ |
|
| 344 |
+ // Update tag |
|
| 345 |
+ tagPath := filepath.Join(registryV2Path, "repositories", remoteRepoName, "_manifests", "tags", "latest", "current", "link") |
|
| 346 |
+ err = ioutil.WriteFile(tagPath, []byte(manifestListDigest.String()), 0644) |
|
| 347 |
+ c.Assert(err, checker.IsNil, check.Commentf("error writing tag link"))
|
|
| 348 |
+ |
|
| 349 |
+ // Verify that the image can be pulled through the manifest list. |
|
| 350 |
+ out, _ := dockerCmd(c, "pull", repoName) |
|
| 351 |
+ |
|
| 352 |
+ // The pull output includes "Digest: <digest>", so find that |
|
| 353 |
+ matches := digestRegex.FindStringSubmatch(out) |
|
| 354 |
+ c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out))
|
|
| 355 |
+ pullDigest := matches[1] |
|
| 356 |
+ |
|
| 357 |
+ // Make sure the pushed and pull digests match |
|
| 358 |
+ c.Assert(manifestListDigest.String(), checker.Equals, pullDigest) |
|
| 359 |
+ |
|
| 360 |
+ // Was the image actually created? |
|
| 361 |
+ dockerCmd(c, "inspect", repoName) |
|
| 362 |
+ |
|
| 363 |
+ dockerCmd(c, "rmi", repoName) |
|
| 364 |
+} |