diff --git a/app/imageoper/checkimage.go b/app/imageoper/checkimage.go index d89c510..1b75a43 100644 --- a/app/imageoper/checkimage.go +++ b/app/imageoper/checkimage.go @@ -6,8 +6,12 @@ package imageoper import ( "context" "encoding/json" + "io" "net/http" + "mstore/pkg/descr" + + ocidigest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -23,44 +27,88 @@ func (oper *Operator) CheckImages(ctx context.Context, params *CheckImagesParams res := &CheckImagesResult{ Repositories: make([]string, 0), } - manDescrs, err := oper.mdb.ListAllManifests(ctx) - if err != nil { - return res, http.StatusInternalServerError, err - } - for _, manDescr := range manDescrs { - oper.logg.Debugf("Check image %s:%s", manDescr.Name, manDescr.Reference) - man := &ocispec.Manifest{} - err = json.Unmarshal([]byte(manDescr.Payload), man) + + var manDescrs []descr.Manifest + if params.Name == "" { + manDescrs, err = oper.mdb.ListAllManifests(ctx) if err != nil { return res, http.StatusInternalServerError, err } - blobs := make([]ocispec.Descriptor, 0) - blobs = append(blobs, man.Config) - blobs = append(blobs, man.Layers...) - incorrectImage := false - for _, blob := range blobs { - oper.logg.Debugf("Check block %s", blob.Digest.String()) - blobExists, blobDescr, err := oper.mdb.GetBlobByNameRefDigest(ctx, manDescr.Name, manDescr.Reference, blob.Digest.String()) - if err != nil { - return res, http.StatusInternalServerError, err - } - blobExists, blobSize, err := oper.store.BlobExists(blobDescr.Name, blobDescr.Digest) - if err != nil { - return res, http.StatusInternalServerError, err - } - if !blobExists || blobSize != blobDescr.Size { - incorrectImage = true - } + } else { + manDescrs, err = oper.mdb.ListManifestsByName(ctx, params.Name) + if err != nil { + return res, http.StatusInternalServerError, err + } + } + for _, manDescr := range manDescrs { + incorrectImage, err := oper.checkImage(ctx, manDescr) + if err != nil { + return res, http.StatusInternalServerError, err } if incorrectImage { repo := manDescr.Name + ":" + manDescr.Reference - oper.logg.Debugf("Delete incomplete image: %s", repo) res.Repositories = append(res.Repositories, repo) - err = oper.deleteManifestObjects(ctx, manDescr.Name, manDescr.Reference) - if err != nil { - return res, http.StatusInternalServerError, err - } } } return res, http.StatusOK, err } + +func (oper *Operator) checkImage(ctx context.Context, manDescr descr.Manifest) (bool, error) { + + resName := manDescr.Name + oper.iLock.WaitAndLock(resName) + defer oper.iLock.Done(resName) + + var err error + incorrectImage := false + oper.logg.Debugf("Check image %s:%s", manDescr.Name, manDescr.Reference) + man := &ocispec.Manifest{} + err = json.Unmarshal([]byte(manDescr.Payload), man) + if err != nil { + return incorrectImage, err + } + blobs := make([]ocispec.Descriptor, 0) + blobs = append(blobs, man.Config) + blobs = append(blobs, man.Layers...) + for _, blob := range blobs { + oper.logg.Debugf("Check blob %s", blob.Digest.String()) + blobExists, blobDescr, err := oper.mdb.GetBlobByNameRefDigest(ctx, manDescr.Name, manDescr.Reference, blob.Digest.String()) + if err != nil { + return incorrectImage, err + } + blobExists, blobSize, err := oper.store.BlobExists(blobDescr.Name, blobDescr.Digest) + if err != nil { + return incorrectImage, err + } + if !blobExists || blobSize != blobDescr.Size { + incorrectImage = true + } else { + digstr := blobDescr.Digest + digobj, err := ocidigest.Parse(digstr) + if err != nil { + oper.logg.Debugf("Incorrect blob name: %s", digstr) + incorrectImage = true + } + _, blobReadCloser, err := oper.store.BlobReader(blobDescr.Name, blobDescr.Digest) + if err != nil { + return incorrectImage, err + } + defer blobReadCloser.Close() + verifier := digobj.Verifier() + _, err = io.Copy(verifier, blobReadCloser) + if !verifier.Verified() { + oper.logg.Debugf("Incorrect blob digest: %s", digstr) + incorrectImage = true + } + } + } + if incorrectImage { + repo := manDescr.Name + ":" + manDescr.Reference + oper.logg.Debugf("Delete incomplete image: %s", repo) + err = oper.deleteManifestObjects(ctx, manDescr.Name, manDescr.Reference) + if err != nil { + return incorrectImage, err + } + } + return incorrectImage, err +} diff --git a/app/service/service.go b/app/service/service.go index 6e3df37..61e3eef 100644 --- a/app/service/service.go +++ b/app/service/service.go @@ -103,6 +103,8 @@ func (svc *Service) Build() error { svc.rout.Post(`/v3/api/grant/delete`, svc.hand.DeleteGrant) svc.rout.Post(`/v3/api/grants/list`, svc.hand.ListGrants) + svc.rout.Get(`/{filepath}`, svc.hand.GetFile) + svc.rout.NotFound(svc.hand.NotFound) selector := svc.rout.Selector()