mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 20:07:55 +08:00
artifacts: initial support for artifacts/notaryv2 spec
https://github.com/oras-project/artifacts-spec https://github.com/notaryproject/notaryproject Fixes issue #264 Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
committed by
Ramkumar Chinchani
parent
d1a80ba9b7
commit
e42e42a2cc
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"testing"
|
||||
|
||||
zerr "github.com/anuvu/zot/errors"
|
||||
"github.com/anuvu/zot/pkg/extensions/monitoring"
|
||||
"github.com/anuvu/zot/pkg/log"
|
||||
"github.com/anuvu/zot/pkg/storage"
|
||||
@@ -717,4 +718,16 @@ func TestNegativeCasesObjectsStorage(t *testing.T) {
|
||||
err := il.DeleteBlob(testImage, d.String())
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test GetReferrers", t, func(c C) {
|
||||
il = createMockStorage(testDir, &StorageDriverMock{
|
||||
deleteFn: func(ctx context.Context, path string) error {
|
||||
return errS3
|
||||
},
|
||||
})
|
||||
d := godigest.FromBytes([]byte(""))
|
||||
_, err := il.GetReferrers(testImage, d.String(), "application/image")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(err, ShouldEqual, zerr.ErrMethodNotSupported)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
zlog "github.com/anuvu/zot/pkg/log"
|
||||
"github.com/anuvu/zot/pkg/storage"
|
||||
guuid "github.com/gofrs/uuid"
|
||||
"github.com/notaryproject/notation-go-lib"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/rs/zerolog"
|
||||
@@ -1018,6 +1019,10 @@ func (is *ObjectStorage) GetBlobContent(repo string, digest string) ([]byte, err
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (is *ObjectStorage) GetReferrers(repo, digest string, mediaType string) ([]notation.Descriptor, error) {
|
||||
return nil, errors.ErrMethodNotSupported
|
||||
}
|
||||
|
||||
func (is *ObjectStorage) GetIndexContent(repo string) ([]byte, error) {
|
||||
dir := path.Join(is.rootDir, repo)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package storage
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/notaryproject/notation-go-lib"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
@@ -40,4 +41,5 @@ type ImageStore interface {
|
||||
DeleteBlob(repo string, digest string) error
|
||||
GetIndexContent(repo string) ([]byte, error)
|
||||
GetBlobContent(repo, digest string) ([]byte, error)
|
||||
GetReferrers(repo, digest string, mediaType string) ([]notation.Descriptor, error)
|
||||
}
|
||||
|
||||
+112
-17
@@ -15,11 +15,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1"
|
||||
|
||||
"github.com/anuvu/zot/errors"
|
||||
"github.com/anuvu/zot/pkg/extensions/monitoring"
|
||||
zlog "github.com/anuvu/zot/pkg/log"
|
||||
apexlog "github.com/apex/log"
|
||||
guuid "github.com/gofrs/uuid"
|
||||
"github.com/notaryproject/notation-go-lib"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/umoci"
|
||||
@@ -437,7 +440,7 @@ func (is *ImageStoreFS) PutImageManifest(repo string, reference string, mediaTyp
|
||||
return "", err
|
||||
}
|
||||
|
||||
if mediaType != ispec.MediaTypeImageManifest {
|
||||
if !IsSupportedMediaType(mediaType) {
|
||||
is.log.Debug().Interface("actual", mediaType).
|
||||
Interface("expected", ispec.MediaTypeImageManifest).Msg("bad manifest media type")
|
||||
return "", errors.ErrBadManifest
|
||||
@@ -448,25 +451,33 @@ func (is *ImageStoreFS) PutImageManifest(repo string, reference string, mediaTyp
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
|
||||
var m ispec.Manifest
|
||||
if err := json.Unmarshal(body, &m); err != nil {
|
||||
is.log.Error().Err(err).Msg("unable to unmarshal JSON")
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
if mediaType == ispec.MediaTypeImageManifest {
|
||||
var m ispec.Manifest
|
||||
if err := json.Unmarshal(body, &m); err != nil {
|
||||
is.log.Error().Err(err).Msg("unable to unmarshal JSON")
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
|
||||
if m.SchemaVersion != SchemaVersion {
|
||||
is.log.Error().Int("SchemaVersion", m.SchemaVersion).Msg("invalid manifest")
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
if m.SchemaVersion != SchemaVersion {
|
||||
is.log.Error().Int("SchemaVersion", m.SchemaVersion).Msg("invalid manifest")
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
|
||||
for _, l := range m.Layers {
|
||||
digest := l.Digest
|
||||
blobPath := is.BlobPath(repo, digest)
|
||||
is.log.Info().Str("blobPath", blobPath).Str("reference", reference).Msg("manifest layers")
|
||||
for _, l := range m.Layers {
|
||||
digest := l.Digest
|
||||
blobPath := is.BlobPath(repo, digest)
|
||||
is.log.Info().Str("blobPath", blobPath).Str("reference", reference).Msg("manifest layers")
|
||||
|
||||
if _, err := os.Stat(blobPath); err != nil {
|
||||
is.log.Error().Err(err).Str("blobPath", blobPath).Msg("unable to find blob")
|
||||
return digest.String(), errors.ErrBlobNotFound
|
||||
if _, err := os.Stat(blobPath); err != nil {
|
||||
is.log.Error().Err(err).Str("blobPath", blobPath).Msg("unable to find blob")
|
||||
return digest.String(), errors.ErrBlobNotFound
|
||||
}
|
||||
}
|
||||
} else if mediaType == artifactspec.MediaTypeArtifactManifest {
|
||||
var m notation.Descriptor
|
||||
if err := json.Unmarshal(body, &m); err != nil {
|
||||
is.log.Error().Err(err).Msg("unable to unmarshal JSON")
|
||||
return "", errors.ErrBadManifest
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1264,6 +1275,90 @@ func (is *ImageStoreFS) DeleteBlob(repo string, digest string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (is *ImageStoreFS) GetReferrers(repo, digest string, mediaType string) ([]notation.Descriptor, error) {
|
||||
dir := path.Join(is.rootDir, repo)
|
||||
if !is.DirExists(dir) {
|
||||
return nil, errors.ErrRepoNotFound
|
||||
}
|
||||
|
||||
gdigest, err := godigest.Parse(digest)
|
||||
if err != nil {
|
||||
is.log.Error().Err(err).Str("digest", digest).Msg("failed to parse digest")
|
||||
return nil, errors.ErrBadBlobDigest
|
||||
}
|
||||
|
||||
is.RLock()
|
||||
defer is.RUnlock()
|
||||
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "index.json"))
|
||||
|
||||
if err != nil {
|
||||
is.log.Error().Err(err).Str("dir", dir).Msg("failed to read index.json")
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.ErrRepoNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
if err := json.Unmarshal(buf, &index); err != nil {
|
||||
is.log.Error().Err(err).Str("dir", dir).Msg("invalid JSON")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
found := false
|
||||
|
||||
result := []notation.Descriptor{}
|
||||
|
||||
for _, m := range index.Manifests {
|
||||
if m.MediaType != artifactspec.MediaTypeArtifactManifest {
|
||||
continue
|
||||
}
|
||||
|
||||
p := path.Join(dir, "blobs", m.Digest.Algorithm().String(), m.Digest.Encoded())
|
||||
|
||||
buf, err = ioutil.ReadFile(p)
|
||||
|
||||
if err != nil {
|
||||
is.log.Error().Err(err).Str("blob", p).Msg("failed to read manifest")
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.ErrManifestNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var manifest artifactspec.Manifest
|
||||
if err := json.Unmarshal(buf, &manifest); err != nil {
|
||||
is.log.Error().Err(err).Str("dir", dir).Msg("invalid JSON")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if mediaType != manifest.ArtifactType || gdigest != manifest.Subject.Digest {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, notation.Descriptor{MediaType: m.MediaType,
|
||||
Digest: m.Digest, Size: m.Size, Annotations: m.Annotations})
|
||||
|
||||
found = true
|
||||
}
|
||||
|
||||
if !found {
|
||||
return nil, errors.ErrManifestNotFound
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func IsSupportedMediaType(mediaType string) bool {
|
||||
return mediaType == ispec.MediaTypeImageManifest ||
|
||||
mediaType == artifactspec.MediaTypeArtifactManifest
|
||||
}
|
||||
|
||||
// garbage collection
|
||||
|
||||
// Scrub will clean up all unreferenced blobs.
|
||||
|
||||
@@ -122,6 +122,16 @@ func TestStorageFSAPIs(t *testing.T) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// invalid GetReferrers
|
||||
_, err = il.GetReferrers("invalid", "invalid", "invalid")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = il.GetReferrers(repoName, "invalid", "invalid")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = il.GetReferrers(repoName, d.String(), "invalid")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// invalid DeleteImageManifest
|
||||
indexPath := path.Join(il.RootDir(), repoName, "index.json")
|
||||
err = os.Chmod(indexPath, 0000)
|
||||
|
||||
Reference in New Issue
Block a user