forked from TrueCloudLab/distribution
275 lines
8.7 KiB
Go
275 lines
8.7 KiB
Go
package migration
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/docker/dhe-deploy/registry/middleware/mocks"
|
|
"github.com/docker/distribution"
|
|
"github.com/docker/distribution/context"
|
|
"github.com/docker/distribution/registry/storage"
|
|
"github.com/docker/distribution/registry/storage/cache/memory"
|
|
"github.com/docker/distribution/registry/storage/driver"
|
|
"github.com/docker/distribution/registry/storage/driver/inmemory"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
const root = "/docker/registry/v2/"
|
|
|
|
type env struct {
|
|
registry distribution.Namespace
|
|
driver driver.StorageDriver
|
|
ctx context.Context
|
|
}
|
|
|
|
func setupRegistry(t *testing.T) *env {
|
|
d := inmemory.New()
|
|
ctx := context.Background()
|
|
registry, err := storage.NewRegistry(
|
|
ctx,
|
|
d,
|
|
storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()),
|
|
storage.EnableRedirect,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("error iunstantiating registry: %v", err)
|
|
}
|
|
|
|
// Add data to registry
|
|
var prefix = root + "repositories/admin/"
|
|
data := map[string]interface{}{
|
|
"content": map[string]string{
|
|
// REPOSITORIES
|
|
//a
|
|
prefix + "a-repo/_layers/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "a-repo/_layers/sha256/6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d/link": "sha256:6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d",
|
|
prefix + "a-repo/_manifests/revisions/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "a-repo/_manifests/tags/a-tag/current/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "a-repo/_manifests/tags/a-tag/index/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
//b
|
|
prefix + "b-repo/_layers/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "b-repo/_layers/sha256/6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d/link": "sha256:6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d",
|
|
prefix + "b-repo/_manifests/revisions/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "b-repo/_manifests/tags/b-tag/current/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
prefix + "b-repo/_manifests/tags/b-tag/index/sha256/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/link": "sha256:1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566",
|
|
// MANIFESTS
|
|
root + "blobs/sha256/1f/1f8d6e1edee77de035d79ca992df4e5cc8d358ec38f527077a84945a79907566/data": V2_MANIFEST_1,
|
|
root + "blobs/sha256/6b/6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d/data": V2_MANIFEST_CONFIG_1,
|
|
},
|
|
}
|
|
for path, blob := range data["content"].(map[string]string) {
|
|
d.PutContent(ctx, path, []byte(blob))
|
|
}
|
|
|
|
return &env{
|
|
registry,
|
|
d,
|
|
ctx,
|
|
}
|
|
}
|
|
|
|
func TestMigrateResumes(t *testing.T) {
|
|
env := setupRegistry(t)
|
|
|
|
tests := []struct {
|
|
migration *migration
|
|
expectedRepos []string
|
|
}{
|
|
{
|
|
migration: &migration{
|
|
reg: env.registry,
|
|
isFromResume: false,
|
|
},
|
|
expectedRepos: []string{"admin/a-repo", "admin/b-repo"},
|
|
},
|
|
{
|
|
migration: &migration{
|
|
reg: env.registry,
|
|
isFromResume: true,
|
|
currentRepo: "admin/b-repo",
|
|
},
|
|
expectedRepos: []string{"admin/b-repo"},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
// Iterate through the repositories, storing each repository name within
|
|
// iteratedRepos. We can then compare which repos were passed to onTagFunc
|
|
// to check resumes
|
|
iteratedRepos := []string{}
|
|
onTagFunc := func(ctx context.Context, repo distribution.Repository, tagName string, tag distribution.Descriptor) error {
|
|
iteratedRepos = append(iteratedRepos, repo.Named().Name())
|
|
return nil
|
|
}
|
|
test.migration.enumerator = NewEnumerator(onTagFunc)
|
|
if _, err := test.migration.Migrate(env.ctx); err != nil {
|
|
t.Fatalf("error migrating: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(iteratedRepos, test.expectedRepos) {
|
|
t.Fatalf("resume failed, expected vs actual repo iteration: %s vs %s", test.expectedRepos, iteratedRepos)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// This is a basic test asserting that there are no obvious errors with
|
|
// the migration logic.
|
|
func TestAddTagAndManifest(t *testing.T) {
|
|
env := setupRegistry(t)
|
|
store := mocks.NewStore()
|
|
migration := NewMigration(env.registry, store)
|
|
|
|
store.TagStore.On(
|
|
"PutTag",
|
|
mock.AnythingOfType("*context.valueCtx"),
|
|
mock.AnythingOfTypeArgument("*storage.repository"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("distribution.Descriptor"),
|
|
).Return(nil).Run(func(a mock.Arguments) {
|
|
fmt.Printf("%#v", a)
|
|
})
|
|
|
|
store.ManifestStore.On(
|
|
"PutManifest",
|
|
mock.AnythingOfType("*context.valueCtx"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("*schema2.DeserializedManifest"),
|
|
).Return(nil).Run(func(a mock.Arguments) {
|
|
fmt.Printf("%#v", a)
|
|
})
|
|
|
|
_, err := migration.Migrate(env.ctx)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error during migration: %s", err)
|
|
}
|
|
}
|
|
|
|
// Assert that failing during a migration returns no error
|
|
// and instead only logs the error
|
|
func TestAddTagAndManifestReturnsNil(t *testing.T) {
|
|
env := setupRegistry(t)
|
|
store := mocks.NewStore()
|
|
migration := NewMigration(env.registry, store)
|
|
|
|
// When we get admin/a-repo we can fail fast.
|
|
store.TagStore.On(
|
|
"PutTag",
|
|
mock.AnythingOfType("*context.valueCtx"),
|
|
mock.AnythingOfTypeArgument("*storage.repository"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("distribution.Descriptor"),
|
|
).Return(nil)
|
|
|
|
store.ManifestStore.On(
|
|
"PutManifest",
|
|
mock.AnythingOfType("*context.valueCtx"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("string"),
|
|
mock.AnythingOfType("*schema2.DeserializedManifest"),
|
|
).Return(nil)
|
|
|
|
_, err := migration.Migrate(env.ctx)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error during migration: %v", err)
|
|
}
|
|
}
|
|
|
|
const V2_MANIFEST_1 = `
|
|
{
|
|
"schemaVersion": 2,
|
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
|
"config": {
|
|
"mediaType": "application/vnd.docker.container.image.v1+json",
|
|
"size": 1473,
|
|
"digest": "sha256:6bf8e372a8396bbf22c0b2e0eebdad5ac3da97357621fe68de694bd4de23639d"
|
|
},
|
|
"layers": [
|
|
{
|
|
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
|
"size": 146,
|
|
"digest": "sha256:c170e8502f05562c30101cd65993e514cf63d242d6f14af6ca49896168c59ffd"
|
|
}
|
|
]
|
|
}
|
|
`
|
|
|
|
const V2_MANIFEST_CONFIG_1 = `
|
|
{
|
|
"architecture": "amd64",
|
|
"config": {
|
|
"Hostname": "9aec87ce8e45",
|
|
"Domainname": "",
|
|
"User": "",
|
|
"AttachStdin": false,
|
|
"AttachStdout": false,
|
|
"AttachStderr": false,
|
|
"Tty": false,
|
|
"OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"Env": [
|
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
],
|
|
"Cmd": [
|
|
"/true"
|
|
],
|
|
"Image": "sha256:bbadf13f1e9e0d1629c07ad1e7eedcc5a6383300b7701c131a6f0beac49866ad",
|
|
"Volumes": null,
|
|
"WorkingDir": "",
|
|
"Entrypoint": null,
|
|
"OnBuild": null,
|
|
"Labels": {
|
|
}
|
|
},
|
|
"container": "dab58e1226ef3b699c25b7befc7cec562707a959135d130f667a039e18e63f72",
|
|
"container_config": {
|
|
"Hostname": "9aec87ce8e45",
|
|
"Domainname": "",
|
|
"User": "",
|
|
"AttachStdin": false,
|
|
"AttachStdout": false,
|
|
"AttachStderr": false,
|
|
"Tty": false,
|
|
"OpenStdin": false,
|
|
"StdinOnce": false,
|
|
"Env": [
|
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
],
|
|
"Cmd": [
|
|
"/bin/sh",
|
|
"-c",
|
|
"#(nop) CMD [\"/true\"]"
|
|
],
|
|
"Image": "sha256:bbadf13f1e9e0d1629c07ad1e7eedcc5a6383300b7701c131a6f0beac49866ad",
|
|
"Volumes": null,
|
|
"WorkingDir": "",
|
|
"Entrypoint": null,
|
|
"OnBuild": null,
|
|
"Labels": {
|
|
}
|
|
},
|
|
"created": "2016-05-19T20:38:48.345518736Z",
|
|
"docker_version": "1.11.1",
|
|
"history": [
|
|
{
|
|
"created": "2016-05-19T20:38:48.277232795Z",
|
|
"created_by": "/bin/sh -c #(nop) ADD file:513005a00bb6ce26c9eb571d6f16e0c12378ba40f8e3100bcb484db53008e3b2 in /true"
|
|
},
|
|
{
|
|
"created": "2016-05-19T20:38:48.345518736Z",
|
|
"created_by": "/bin/sh -c #(nop) CMD [\"/true\"]",
|
|
"empty_layer": true
|
|
}
|
|
],
|
|
"os": "linux",
|
|
"rootfs": {
|
|
"type": "layers",
|
|
"diff_ids": [
|
|
"sha256:af593d271f82964b57d51cc5e647c6076fb160bf8620f605848130110f0ed647"
|
|
]
|
|
}
|
|
}
|
|
`
|