2023-05-31 12:26:23 -05:00
|
|
|
//go:build sync
|
|
|
|
// +build sync
|
|
|
|
|
2021-06-08 15:11:18 -05:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
2022-10-06 11:41:16 -05:00
|
|
|
"bytes"
|
2021-06-08 15:11:18 -05:00
|
|
|
"context"
|
2021-10-28 04:10:01 -05:00
|
|
|
"encoding/json"
|
2021-06-08 15:11:18 -05:00
|
|
|
"fmt"
|
2021-10-28 04:10:01 -05:00
|
|
|
"os"
|
2023-06-21 13:05:52 -05:00
|
|
|
"path"
|
2021-06-08 15:11:18 -05:00
|
|
|
"testing"
|
|
|
|
|
2023-06-21 13:05:52 -05:00
|
|
|
dockerManifest "github.com/containers/image/v5/manifest"
|
2023-05-31 12:26:23 -05:00
|
|
|
"github.com/containers/image/v5/oci/layout"
|
2021-06-08 15:11:18 -05:00
|
|
|
"github.com/containers/image/v5/types"
|
2021-10-28 04:10:01 -05:00
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
"github.com/rs/zerolog"
|
2021-06-08 15:11:18 -05:00
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
2022-10-20 11:39:20 -05:00
|
|
|
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/errors"
|
2023-05-31 12:26:23 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/config"
|
2023-06-22 12:43:47 -05:00
|
|
|
syncconf "zotregistry.io/zot/pkg/extensions/config/sync"
|
2023-05-31 12:26:23 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/lint"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/monitoring"
|
2023-05-31 12:26:23 -05:00
|
|
|
client "zotregistry.io/zot/pkg/extensions/sync/httpclient"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/log"
|
|
|
|
"zotregistry.io/zot/pkg/storage"
|
2023-05-31 12:26:23 -05:00
|
|
|
"zotregistry.io/zot/pkg/storage/cache"
|
2023-05-26 13:08:19 -05:00
|
|
|
storageConstants "zotregistry.io/zot/pkg/storage/constants"
|
2022-09-30 12:35:16 -05:00
|
|
|
"zotregistry.io/zot/pkg/storage/local"
|
2021-12-17 11:34:22 -05:00
|
|
|
"zotregistry.io/zot/pkg/test"
|
2023-05-26 13:08:19 -05:00
|
|
|
"zotregistry.io/zot/pkg/test/inject"
|
2022-10-06 11:41:16 -05:00
|
|
|
"zotregistry.io/zot/pkg/test/mocks"
|
2021-06-08 15:11:18 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
testImage = "zot-test"
|
|
|
|
testImageTag = "0.0.1"
|
|
|
|
|
|
|
|
host = "127.0.0.1:45117"
|
|
|
|
)
|
|
|
|
|
2023-03-09 13:41:48 -05:00
|
|
|
var ErrTestError = fmt.Errorf("testError")
|
|
|
|
|
2022-02-18 06:36:50 -05:00
|
|
|
func TestInjectSyncUtils(t *testing.T) {
|
|
|
|
Convey("Inject errors in utils functions", t, func() {
|
|
|
|
repositoryReference := fmt.Sprintf("%s/%s", host, testImage)
|
|
|
|
ref, err := parseRepositoryReference(repositoryReference)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(ref.Name(), ShouldEqual, repositoryReference)
|
|
|
|
|
2023-05-26 13:08:19 -05:00
|
|
|
injected := inject.InjectFailure(0)
|
2022-02-18 06:36:50 -05:00
|
|
|
if injected {
|
2023-05-31 12:26:23 -05:00
|
|
|
_, err = getRepoTags(context.Background(), &types.SystemContext{}, host, testImage)
|
2022-02-18 06:36:50 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
}
|
|
|
|
|
2023-05-26 13:08:19 -05:00
|
|
|
injected = inject.InjectFailure(0)
|
2023-05-31 12:26:23 -05:00
|
|
|
_, err = getPolicyContext(log.NewLogger("debug", ""))
|
2022-02-18 06:36:50 -05:00
|
|
|
if injected {
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
} else {
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}
|
|
|
|
|
|
|
|
log := log.Logger{Logger: zerolog.New(os.Stdout)}
|
|
|
|
metrics := monitoring.NewMetricsServer(false, log)
|
2023-05-26 13:08:19 -05:00
|
|
|
imageStore := local.NewImageStore(t.TempDir(), false, storageConstants.DefaultGCDelay,
|
2022-11-02 17:53:08 -05:00
|
|
|
false, false, log, metrics, nil, nil,
|
2022-06-24 08:08:47 -05:00
|
|
|
)
|
2023-05-26 13:08:19 -05:00
|
|
|
injected = inject.InjectFailure(0)
|
2022-04-05 10:18:31 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
ols := NewOciLayoutStorage(storage.StoreController{DefaultStore: imageStore})
|
|
|
|
_, err = ols.GetImageReference(testImage, testImageTag)
|
2022-02-18 06:36:50 -05:00
|
|
|
if injected {
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
} else {
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-06-08 15:11:18 -05:00
|
|
|
func TestSyncInternal(t *testing.T) {
|
2021-10-28 04:10:01 -05:00
|
|
|
Convey("Verify parseRepositoryReference func", t, func() {
|
2021-06-08 15:11:18 -05:00
|
|
|
repositoryReference := fmt.Sprintf("%s/%s", host, testImage)
|
|
|
|
ref, err := parseRepositoryReference(repositoryReference)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(ref.Name(), ShouldEqual, repositoryReference)
|
|
|
|
|
|
|
|
repositoryReference = fmt.Sprintf("%s/%s:tagged", host, testImage)
|
|
|
|
_, err = parseRepositoryReference(repositoryReference)
|
|
|
|
So(err, ShouldEqual, errors.ErrInvalidRepositoryName)
|
|
|
|
|
|
|
|
repositoryReference = fmt.Sprintf("http://%s/%s", host, testImage)
|
|
|
|
_, err = parseRepositoryReference(repositoryReference)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
repositoryReference = fmt.Sprintf("docker://%s/%s", host, testImage)
|
|
|
|
_, err = parseRepositoryReference(repositoryReference)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
_, err = getFileCredentials("/path/to/inexistent/file")
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
2022-09-02 07:56:02 -05:00
|
|
|
tempFile, err := os.CreateTemp("", "sync-credentials-")
|
2021-06-08 15:11:18 -05:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
content := []byte(`{`)
|
2022-09-02 07:56:02 -05:00
|
|
|
if err := os.WriteFile(tempFile.Name(), content, 0o600); err != nil {
|
2021-06-08 15:11:18 -05:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2021-12-13 14:23:31 -05:00
|
|
|
_, err = getFileCredentials(tempFile.Name())
|
2021-06-08 15:11:18 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
srcCtx := &types.SystemContext{}
|
2023-05-31 12:26:23 -05:00
|
|
|
_, err = getRepoTags(context.Background(), srcCtx, host, testImage)
|
2021-06-08 15:11:18 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
_, err = getRepoTags(context.Background(), srcCtx, host, testImage)
|
2021-06-08 15:11:18 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
_, err = getFileCredentials("/invalid/path/to/file")
|
|
|
|
So(err, ShouldNotBeNil)
|
2021-12-29 10:14:56 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
ok := isSupportedMediaType("unknown")
|
|
|
|
So(ok, ShouldBeFalse)
|
2021-10-28 04:10:01 -05:00
|
|
|
})
|
2023-05-31 12:26:23 -05:00
|
|
|
}
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
func TestRemoteRegistry(t *testing.T) {
|
|
|
|
Convey("test remote registry", t, func() {
|
|
|
|
logger := log.NewLogger("debug", "")
|
|
|
|
cfg := client.Config{
|
|
|
|
URL: "url",
|
|
|
|
TLSVerify: false,
|
2021-10-28 04:10:01 -05:00
|
|
|
}
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
client, err := client.New(cfg, logger)
|
2022-12-22 13:19:42 -05:00
|
|
|
So(err, ShouldBeNil)
|
2022-01-27 07:45:46 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
remote := NewRemoteRegistry(client, logger)
|
|
|
|
imageRef, err := layout.NewReference("dir", "image")
|
2022-12-22 13:19:42 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
_, _, _, err = remote.GetManifestContent(imageRef)
|
2021-12-29 10:14:56 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
tags, err := remote.GetRepoTags("repo")
|
|
|
|
So(tags, ShouldBeEmpty)
|
2021-12-29 10:14:56 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
2021-10-28 04:10:01 -05:00
|
|
|
})
|
2023-05-31 12:26:23 -05:00
|
|
|
}
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-06-22 12:43:47 -05:00
|
|
|
func TestService(t *testing.T) {
|
|
|
|
Convey("trigger fetch tags error", t, func() {
|
|
|
|
conf := syncconf.RegistryConfig{
|
|
|
|
URLs: []string{"http://localhost"},
|
|
|
|
}
|
|
|
|
|
2023-07-18 12:27:26 -05:00
|
|
|
service, err := New(conf, "", storage.StoreController{}, mocks.MetaDBMock{}, log.Logger{})
|
2023-06-22 12:43:47 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = service.SyncRepo("repo")
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
func TestLocalRegistry(t *testing.T) {
|
|
|
|
Convey("make StoreController", t, func() {
|
|
|
|
dir := t.TempDir()
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2022-01-10 11:06:12 -05:00
|
|
|
log := log.NewLogger("debug", "")
|
2022-11-22 13:13:08 -05:00
|
|
|
metrics := monitoring.NewMetricsServer(false, log)
|
2023-05-31 12:26:23 -05:00
|
|
|
cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
|
|
|
|
RootDir: dir,
|
|
|
|
Name: "cache",
|
|
|
|
UseRelPaths: true,
|
|
|
|
}, log)
|
2022-11-22 13:13:08 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
syncImgStore := local.NewImageStore(dir, true, storageConstants.DefaultGCDelay,
|
|
|
|
true, true, log, metrics, nil, cacheDriver)
|
|
|
|
repoName := "repo"
|
2021-12-17 11:34:22 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, nil, log)
|
|
|
|
imageReference, err := registry.GetImageReference(repoName, "1.0")
|
2021-12-17 11:34:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
So(imageReference, ShouldNotBeNil)
|
2021-12-17 11:34:22 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
imgStore := getImageStoreFromImageReference(imageReference, repoName, "1.0")
|
2021-12-17 11:34:22 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// create a blob/layer
|
|
|
|
upload, err := imgStore.NewBlobUpload(repoName)
|
2021-12-17 11:34:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
So(upload, ShouldNotBeEmpty)
|
2021-12-17 11:34:22 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
content := []byte("this is a blob1")
|
|
|
|
buf := bytes.NewBuffer(content)
|
|
|
|
buflen := buf.Len()
|
|
|
|
digest := godigest.FromBytes(content)
|
|
|
|
So(digest, ShouldNotBeNil)
|
|
|
|
blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
|
2022-10-22 02:26:14 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
So(blob, ShouldEqual, buflen)
|
|
|
|
bdgst1 := digest
|
|
|
|
bsize1 := len(content)
|
2022-10-22 02:26:14 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = imgStore.FinishBlobUpload(repoName, upload, buf, digest)
|
2023-02-13 13:43:52 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
So(blob, ShouldEqual, buflen)
|
2023-02-13 13:43:52 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// push index image
|
2023-02-13 13:43:52 -05:00
|
|
|
var index ispec.Index
|
2023-05-31 12:26:23 -05:00
|
|
|
index.SchemaVersion = 2
|
|
|
|
index.MediaType = ispec.MediaTypeImageIndex
|
2023-02-13 13:43:52 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
for i := 0; i < 4; i++ {
|
|
|
|
// upload image config blob
|
|
|
|
upload, err := imgStore.NewBlobUpload(repoName)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(upload, ShouldNotBeEmpty)
|
2023-02-13 13:43:52 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
cblob, cdigest := test.GetRandomImageConfig()
|
|
|
|
buf := bytes.NewBuffer(cblob)
|
|
|
|
buflen := buf.Len()
|
|
|
|
blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
2021-12-17 11:34:22 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = imgStore.FinishBlobUpload(repoName, upload, buf, cdigest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
2023-05-10 12:15:33 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// create a manifest
|
|
|
|
manifest := ispec.Manifest{
|
|
|
|
Config: ispec.Descriptor{
|
|
|
|
MediaType: ispec.MediaTypeImageConfig,
|
|
|
|
Digest: cdigest,
|
|
|
|
Size: int64(len(cblob)),
|
2023-05-10 12:15:33 -05:00
|
|
|
},
|
2023-05-31 12:26:23 -05:00
|
|
|
Layers: []ispec.Descriptor{
|
|
|
|
{
|
|
|
|
MediaType: ispec.MediaTypeImageLayer,
|
|
|
|
Digest: bdgst1,
|
|
|
|
Size: int64(bsize1),
|
2023-05-10 12:15:33 -05:00
|
|
|
},
|
|
|
|
},
|
2023-05-31 12:26:23 -05:00
|
|
|
}
|
|
|
|
manifest.SchemaVersion = 2
|
|
|
|
content, err = json.Marshal(manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
digest = godigest.FromBytes(content)
|
|
|
|
So(digest, ShouldNotBeNil)
|
|
|
|
_, _, err = imgStore.PutImageManifest(repoName, digest.String(), ispec.MediaTypeImageManifest, content)
|
|
|
|
So(err, ShouldBeNil)
|
2023-05-10 12:15:33 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
index.Manifests = append(index.Manifests, ispec.Descriptor{
|
|
|
|
Digest: digest,
|
|
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
|
|
Size: int64(len(content)),
|
|
|
|
})
|
2021-11-25 07:04:39 -05:00
|
|
|
}
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// upload index image
|
|
|
|
indexContent, err := json.Marshal(index)
|
2022-10-22 02:26:14 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
indexDigest := godigest.FromBytes(indexContent)
|
|
|
|
So(indexDigest, ShouldNotBeNil)
|
2022-01-10 11:06:12 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
_, _, err = imgStore.PutImageManifest(repoName, "1.0", ispec.MediaTypeImageIndex, indexContent)
|
2021-10-28 04:10:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("sync index image", func() {
|
|
|
|
ok, err := registry.CanSkipImage(repoName, "1.0", indexDigest)
|
|
|
|
So(ok, ShouldBeFalse)
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
2022-04-05 10:18:31 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2022-04-05 10:18:31 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("trigger GetImageManifest error in CommitImage()", func() {
|
|
|
|
err = os.Chmod(imgStore.BlobPath(repoName, indexDigest), 0o000)
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("trigger linter error in CommitImage()", func() {
|
|
|
|
defaultVal := true
|
|
|
|
linter := lint.NewLinter(&config.LintConfig{
|
|
|
|
BaseConfig: config.BaseConfig{
|
|
|
|
Enable: &defaultVal,
|
|
|
|
},
|
|
|
|
MandatoryAnnotations: []string{"annot1"},
|
|
|
|
}, log)
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
syncImgStore := local.NewImageStore(dir, true, storageConstants.DefaultGCDelay,
|
|
|
|
true, true, log, metrics, linter, cacheDriver)
|
|
|
|
repoName := "repo"
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, nil, log)
|
2021-10-28 04:10:01 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("trigger GetBlobContent on manifest error in CommitImage()", func() {
|
|
|
|
err = os.Chmod(imgStore.BlobPath(repoName, digest), 0o000)
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("trigger copyBlob() error in CommitImage()", func() {
|
|
|
|
err = os.Chmod(imgStore.BlobPath(repoName, bdgst1), 0o000)
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("trigger PutImageManifest error on index manifest in CommitImage()", func() {
|
|
|
|
err = os.MkdirAll(syncImgStore.BlobPath(repoName, indexDigest), storageConstants.DefaultDirPerms)
|
2023-03-09 13:41:48 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = os.Chmod(syncImgStore.BlobPath(repoName, indexDigest), 0o000)
|
2023-03-09 13:41:48 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2023-03-09 13:41:48 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
2023-07-18 12:27:26 -05:00
|
|
|
Convey("trigger metaDB error on index manifest in CommitImage()", func() {
|
|
|
|
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{
|
2023-05-31 12:26:23 -05:00
|
|
|
SetRepoReferenceFn: func(repo, Reference string, manifestDigest godigest.Digest, mediaType string) error {
|
|
|
|
if Reference == "1.0" {
|
|
|
|
return errors.ErrRepoMetaNotFound
|
|
|
|
}
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}, log)
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-07-18 12:27:26 -05:00
|
|
|
Convey("trigger metaDB error on image manifest in CommitImage()", func() {
|
|
|
|
registry := NewLocalRegistry(storage.StoreController{DefaultStore: syncImgStore}, mocks.MetaDBMock{
|
2023-05-31 12:26:23 -05:00
|
|
|
SetRepoReferenceFn: func(repo, Reference string, manifestDigest godigest.Digest, mediaType string) error {
|
|
|
|
return errors.ErrRepoMetaNotFound
|
|
|
|
},
|
|
|
|
}, log)
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = registry.CommitImage(imageReference, repoName, "1.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
2023-05-31 12:26:23 -05:00
|
|
|
})
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
Convey("push image", func() {
|
|
|
|
imageReference, err := registry.GetImageReference(repoName, "2.0")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(imageReference, ShouldNotBeNil)
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
imgStore := getImageStoreFromImageReference(imageReference, repoName, "2.0")
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// upload image
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// create a blob/layer
|
|
|
|
upload, err := imgStore.NewBlobUpload(repoName)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(upload, ShouldNotBeEmpty)
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
content := []byte("this is a blob1")
|
|
|
|
buf := bytes.NewBuffer(content)
|
|
|
|
buflen := buf.Len()
|
|
|
|
digest := godigest.FromBytes(content)
|
|
|
|
So(digest, ShouldNotBeNil)
|
|
|
|
blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
|
|
|
bdgst1 := digest
|
|
|
|
bsize1 := len(content)
|
2022-10-06 11:41:16 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = imgStore.FinishBlobUpload(repoName, upload, buf, digest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
2022-03-10 10:39:11 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// upload image config blob
|
|
|
|
upload, err = imgStore.NewBlobUpload(repoName)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(upload, ShouldNotBeEmpty)
|
2022-03-10 10:39:11 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
cblob, cdigest := test.GetRandomImageConfig()
|
|
|
|
buf = bytes.NewBuffer(cblob)
|
|
|
|
buflen = buf.Len()
|
|
|
|
blob, err = imgStore.PutBlobChunkStreamed(repoName, upload, buf)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
2022-03-10 10:39:11 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
err = imgStore.FinishBlobUpload(repoName, upload, buf, cdigest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(blob, ShouldEqual, buflen)
|
2022-04-14 14:07:44 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
// create a manifest
|
|
|
|
manifest := ispec.Manifest{
|
2022-04-14 14:07:44 -05:00
|
|
|
Config: ispec.Descriptor{
|
2023-05-31 12:26:23 -05:00
|
|
|
MediaType: ispec.MediaTypeImageConfig,
|
|
|
|
Digest: cdigest,
|
|
|
|
Size: int64(len(cblob)),
|
2022-04-14 14:07:44 -05:00
|
|
|
},
|
|
|
|
Layers: []ispec.Descriptor{
|
|
|
|
{
|
2023-05-31 12:26:23 -05:00
|
|
|
MediaType: ispec.MediaTypeImageLayer,
|
|
|
|
Digest: bdgst1,
|
|
|
|
Size: int64(bsize1),
|
2022-04-14 14:07:44 -05:00
|
|
|
},
|
|
|
|
},
|
2023-05-31 12:26:23 -05:00
|
|
|
}
|
|
|
|
manifest.SchemaVersion = 2
|
|
|
|
content, err = json.Marshal(manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
digest = godigest.FromBytes(content)
|
|
|
|
So(digest, ShouldNotBeNil)
|
2022-04-14 14:07:44 -05:00
|
|
|
|
2023-05-31 12:26:23 -05:00
|
|
|
_, _, err = imgStore.PutImageManifest(repoName, "2.0", ispec.MediaTypeImageManifest, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
Convey("sync image", func() {
|
|
|
|
ok, err := registry.CanSkipImage(repoName, "2.0", digest)
|
|
|
|
So(ok, ShouldBeFalse)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = registry.CommitImage(imageReference, repoName, "2.0")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
})
|
|
|
|
})
|
2022-04-14 14:07:44 -05:00
|
|
|
})
|
|
|
|
}
|
2023-06-21 13:05:52 -05:00
|
|
|
|
|
|
|
func TestConvertDockerToOCI(t *testing.T) {
|
|
|
|
Convey("test converting docker to oci functions", t, func() {
|
|
|
|
dir := t.TempDir()
|
|
|
|
|
2023-08-18 03:46:11 -05:00
|
|
|
srcStorageCtlr := test.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
|
|
|
|
|
|
|
|
err := test.WriteImageToFileSystem(test.CreateDefaultImage(), "zot-test", "0.0.1", srcStorageCtlr)
|
|
|
|
So(err, ShouldBeNil)
|
2023-06-21 13:05:52 -05:00
|
|
|
|
|
|
|
imageRef, err := layout.NewReference(path.Join(dir, "zot-test"), "0.0.1")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
imageSource, err := imageRef.NewImageSource(context.Background(), &types.SystemContext{})
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
defer imageSource.Close()
|
|
|
|
|
|
|
|
Convey("trigger Unmarshal manifest error", func() {
|
|
|
|
_, err = convertDockerManifestToOCI(imageSource, []byte{})
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("trigger getImageConfigContent() error", func() {
|
|
|
|
manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
var manifest ispec.Manifest
|
|
|
|
|
|
|
|
err = json.Unmarshal(manifestBuf, &manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = os.Chmod(path.Join(dir, "zot-test", "blobs/sha256", manifest.Config.Digest.Encoded()), 0o000)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("trigger Unmarshal config error", func() {
|
|
|
|
manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
var manifest ispec.Manifest
|
|
|
|
|
|
|
|
err = json.Unmarshal(manifestBuf, &manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", manifest.Config.Digest.Encoded()),
|
|
|
|
[]byte{}, storageConstants.DefaultFilePerms)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("trigger convertDockerLayersToOCI error", func() {
|
|
|
|
manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
var manifest ispec.Manifest
|
|
|
|
|
|
|
|
err = json.Unmarshal(manifestBuf, &manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
manifestDigest := godigest.FromBytes(manifestBuf)
|
|
|
|
|
|
|
|
manifest.Layers[0].MediaType = "unknown"
|
|
|
|
|
|
|
|
newManifest, err := json.Marshal(manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", manifestDigest.Encoded()),
|
|
|
|
newManifest, storageConstants.DefaultFilePerms)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("trigger convertDockerIndexToOCI error", func() {
|
|
|
|
manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerIndexToOCI(imageSource, manifestBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
// make zot-test image an index image
|
|
|
|
|
|
|
|
var manifest ispec.Manifest
|
|
|
|
|
|
|
|
err = json.Unmarshal(manifestBuf, &manifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
dockerNewManifest := ispec.Manifest{
|
|
|
|
MediaType: dockerManifest.DockerV2Schema2MediaType,
|
|
|
|
Config: manifest.Config,
|
|
|
|
Layers: manifest.Layers,
|
|
|
|
}
|
|
|
|
|
|
|
|
dockerNewManifestBuf, err := json.Marshal(dockerNewManifest)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
dockerManifestDigest := godigest.FromBytes(manifestBuf)
|
|
|
|
|
|
|
|
err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", dockerManifestDigest.Encoded()),
|
|
|
|
dockerNewManifestBuf, storageConstants.DefaultFilePerms)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
var index ispec.Index
|
|
|
|
|
|
|
|
index.Manifests = append(index.Manifests, ispec.Descriptor{
|
|
|
|
Digest: dockerManifestDigest,
|
|
|
|
Size: int64(len(dockerNewManifestBuf)),
|
|
|
|
MediaType: dockerManifest.DockerV2Schema2MediaType,
|
|
|
|
})
|
|
|
|
|
|
|
|
index.MediaType = dockerManifest.DockerV2ListMediaType
|
|
|
|
|
|
|
|
dockerIndexBuf, err := json.Marshal(index)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
dockerIndexDigest := godigest.FromBytes(dockerIndexBuf)
|
|
|
|
|
|
|
|
err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", dockerIndexDigest.Encoded()),
|
|
|
|
dockerIndexBuf, storageConstants.DefaultFilePerms)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// write index.json
|
|
|
|
|
|
|
|
var indexJSON ispec.Index
|
|
|
|
|
|
|
|
indexJSONBuf, err := os.ReadFile(path.Join(dir, "zot-test", "index.json"))
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = json.Unmarshal(indexJSONBuf, &indexJSON)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
indexJSON.Manifests = append(indexJSON.Manifests, ispec.Descriptor{
|
|
|
|
Digest: dockerIndexDigest,
|
|
|
|
Size: int64(len(dockerIndexBuf)),
|
|
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ispec.AnnotationRefName: "0.0.2",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
indexJSONBuf, err = json.Marshal(indexJSON)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
err = os.WriteFile(path.Join(dir, "zot-test", "index.json"), indexJSONBuf, storageConstants.DefaultFilePerms)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
imageRef, err := layout.NewReference(path.Join(dir, "zot-test"), "0.0.2")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
imageSource, err := imageRef.NewImageSource(context.Background(), &types.SystemContext{})
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerIndexToOCI(imageSource, dockerIndexBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
err = os.Chmod(path.Join(dir, "zot-test", "blobs/sha256", dockerManifestDigest.Encoded()), 0o000)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
_, err = convertDockerIndexToOCI(imageSource, dockerIndexBuf)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConvertDockerLayersToOCI(t *testing.T) {
|
|
|
|
Convey("test converting docker to oci functions", t, func() {
|
|
|
|
dockerLayers := []ispec.Descriptor{
|
|
|
|
{
|
|
|
|
MediaType: dockerManifest.DockerV2Schema2ForeignLayerMediaType,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
MediaType: dockerManifest.DockerV2Schema2ForeignLayerMediaTypeGzip,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
MediaType: dockerManifest.DockerV2SchemaLayerMediaTypeUncompressed,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
MediaType: dockerManifest.DockerV2Schema2LayerMediaType,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := convertDockerLayersToOCI(dockerLayers)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
So(dockerLayers[0].MediaType, ShouldEqual, ispec.MediaTypeImageLayerNonDistributable) //nolint: staticcheck
|
|
|
|
So(dockerLayers[1].MediaType, ShouldEqual, ispec.MediaTypeImageLayerNonDistributableGzip) //nolint: staticcheck
|
|
|
|
So(dockerLayers[2].MediaType, ShouldEqual, ispec.MediaTypeImageLayer)
|
|
|
|
So(dockerLayers[3].MediaType, ShouldEqual, ispec.MediaTypeImageLayerGzip)
|
|
|
|
})
|
|
|
|
}
|