From 5ec5592a13403cb49896f2a63d0d875f7718d0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 23 Feb 2026 18:38:45 +0200 Subject: [PATCH] return index on get magifest --- app/maindb/file_test.go | 4 +-- app/maindb/grant_test.go | 6 ++-- app/maindb/manifest.go | 55 +++++++++++++++++++++++++----------- app/maindb/scheme.go | 25 +++++++++-------- app/operator/manifest.go | 60 +++++++++++++++++++++++++++------------- app/operator/ociaux.go | 39 ++++++++++++++++++++++++++ pkg/auxoci/ociaux.go | 5 ++++ pkg/descr/manifest.go | 23 ++++++++------- 8 files changed, 156 insertions(+), 61 deletions(-) diff --git a/app/maindb/file_test.go b/app/maindb/file_test.go index 751a279..30ff1a3 100644 --- a/app/maindb/file_test.go +++ b/app/maindb/file_test.go @@ -33,9 +33,9 @@ func TestFile(t *testing.T) { err = db.InitDatabase() require.NoError(t, err) - id := uuid.NewUUID() + id := auxuuid.NewUUID() timenow := auxtool.TimeNow() - creator := uuid.NewUUID() + creator := auxuuid.NewUUID() collection := "foo" newFile := &descr.File{ ID: id, diff --git a/app/maindb/grant_test.go b/app/maindb/grant_test.go index fff66ae..884336c 100644 --- a/app/maindb/grant_test.go +++ b/app/maindb/grant_test.go @@ -34,10 +34,10 @@ func TestGrant(t *testing.T) { err = db.InitDatabase() require.NoError(t, err) - id := uuid.NewUUID() - accountID := uuid.NewUUID() + id := auxuuid.NewUUID() + accountID := auxuuid.NewUUID() timenow := auxtool.TimeNow() - creator := uuid.NewUUID() + creator := auxuuid.NewUUID() newGrant := &descr.Grant{ ID: id, AccountID: accountID, diff --git a/app/maindb/manifest.go b/app/maindb/manifest.go index c1ad5c7..8766c55 100644 --- a/app/maindb/manifest.go +++ b/app/maindb/manifest.go @@ -19,12 +19,13 @@ func (db *Database) InsertManifest(ctx context.Context, manifest *descr.Manifest var err error var request string request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest, - created_at, updated_at, created_by, updated_by) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)` + created_at, updated_at, created_by, updated_by, architecture, os, variant) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)` _, err = db.db.Exec(request, manifest.ID, manifest.Name, manifest.Reference, manifest.ContentType, manifest.Payload, manifest.Digest, manifest.CreatedAt, manifest.UpdatedAt, - manifest.CreatedBy, manifest.UpdatedBy) + manifest.CreatedBy, manifest.UpdatedBy, + manifest.Architecture, manifest.OS, manifest.Variant) if err != nil { return err } @@ -39,12 +40,14 @@ func (db *Database) InsertManifests(ctx context.Context, manifests []*descr.Mani for _, manifest := range manifests { var request string request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest, - created_at, updated_at, created_by, updated_by) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)` + created_at, updated_at, created_by, updated_by, + architecture, os, variant) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)` _, err = tx.Exec(request, manifest.ID, manifest.Name, manifest.Reference, manifest.ContentType, manifest.Payload, manifest.Digest, manifest.CreatedAt, manifest.UpdatedAt, - manifest.CreatedBy, manifest.UpdatedBy) + manifest.CreatedBy, manifest.UpdatedBy, + manifest.Architecture, manifest.OS, manifest.Variant) if err != nil { return err } @@ -62,9 +65,10 @@ func (db *Database) UpdateManifest(ctx context.Context, manifest *descr.Manifest var request string // Manifest request = `UPDATE manifests SET contentType = $1, payload = $2, digest = $3, updated_at = $4 - WHERE name = $5 AND reference = $6` + WHERE name = $5 AND reference = $6, architecture = $7, os = $8, variant = $9` _, err = db.db.Exec(request, manifest.ContentType, manifest.Payload, manifest.Digest, - manifest.UpdatedAt, manifest.Name, manifest.Reference) + manifest.UpdatedAt, manifest.Name, manifest.Reference, + manifest.Architecture, manifest.OS, manifest.Variant) if err != nil { return err } @@ -80,12 +84,13 @@ func (db *Database) InsertManifestWithLayers(ctx context.Context, manifest *desc // Manifest request = ` INSERT INTO manifests(id, name, reference, contentType, payload, digest, - created_at, updated_at, created_by, updated_by) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);` + created_at, updated_at, created_by, updated_by, architecture, os, variant) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);` _, err = tx.Exec(request, manifest.ID, manifest.Name, manifest.Reference, manifest.ContentType, manifest.Payload, manifest.Digest, manifest.CreatedAt, manifest.UpdatedAt, - manifest.CreatedBy, manifest.UpdatedBy) + manifest.CreatedBy, manifest.UpdatedBy, + manifest.Architecture, manifest.OS, manifest.Variant) if err != nil { return err } @@ -124,10 +129,11 @@ func (db *Database) UpdateManifestWithBlobs(ctx context.Context, manifest *descr // Manifest request = `UPDATE manifests SET contentType = $1, payload = $2, digest = $3, updated_at = $4, updated_by = $5 - WHERE name = $6 AND reference = $7` + WHERE name = $6 AND reference = $7, architecture = $8, os = $9, variant = $10` _, err = tx.Exec(request, manifest.ContentType, manifest.Payload, manifest.Digest, manifest.UpdatedAt, manifest.UpdatedBy, - manifest.Name, manifest.Reference) + manifest.Name, manifest.Reference, + manifest.Architecture, manifest.OS, manifest.Variant) if err != nil { return err } @@ -202,20 +208,37 @@ func (db *Database) GetManifestByDigest(ctx context.Context, name, digest string return exists, manifest, err } -func (db *Database) GetManifestByReference(ctx context.Context, name, reference string) (bool, descr.Manifest, error) { +func (db *Database) GetManifestsByReference(ctx context.Context, name, reference string) (bool, []descr.Manifest, error) { var err error - manifest := descr.Manifest{} exists := false manifests := make([]descr.Manifest, 0) request := `SELECT * FROM manifests WHERE name = $1 AND reference = $2 LIMIT 1` err = db.db.Select(&manifests, request, name, reference) if err != nil { - return exists, manifest, err + return exists, manifests, err } if len(manifests) > 0 { exists = true + } + return exists, manifests, err +} + +func (db *Database) GetManifestsByReferenceArchitecture(ctx context.Context, name, reference, architecture, os, variant string) (bool, descr.Manifest, error) { + var err error + exists := false + manifest := descr.Manifest{} + manifests := make([]descr.Manifest, 0) + request := `SELECT * FROM manifests WHERE name = $1 AND reference = $2 + AND architecture = $3 AND os = $4 AND variant = $5 LIMIT 1000` + err = db.db.Select(&manifests, request, name, reference, architecture, os, variant) + if err != nil { + return exists, manifest, err + } + + if len(manifests) > 0 { manifest = manifests[0] + exists = true } return exists, manifest, err } diff --git a/app/maindb/scheme.go b/app/maindb/scheme.go index 1dbadd8..26e4008 100644 --- a/app/maindb/scheme.go +++ b/app/maindb/scheme.go @@ -27,19 +27,22 @@ const schema = ` --- DROP TABLE IF EXISTS manifests; CREATE TABLE IF NOT EXISTS manifests ( - id VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - reference VARCHAR(255) NOT NULL, - digest VARCHAR(1024) NOT NULL, - contentType VARCHAR(255) NOT NULL, - payload VARCHAR(4096) NOT NULL, - created_at VARCHAR(255) NOT NULL, - updated_at VARCHAR(255) NOT NULL, - created_by VARCHAR(255) NOT NULL, - updated_by VARCHAR(255) NOT NULL + id VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + reference VARCHAR(255) NOT NULL, + digest VARCHAR(1024) NOT NULL, + contentType VARCHAR(255) NOT NULL, + payload VARCHAR(4096) NOT NULL, + created_at VARCHAR(255) NOT NULL, + updated_at VARCHAR(255) NOT NULL, + created_by VARCHAR(255) NOT NULL, + updated_by VARCHAR(255) NOT NULL, + architecture VARCHAR(255) NOT NULL, + os VARCHAR(255) NOT NULL, + variant VARCHAR(255) NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS manifests_index - ON manifests(name, reference); + ON manifests(name, reference, architecture, os, variant); CREATE TABLE IF NOT EXISTS blobs ( id VARCHAR(255) NOT NULL, diff --git a/app/operator/manifest.go b/app/operator/manifest.go index 3806ea2..eab099d 100644 --- a/app/operator/manifest.go +++ b/app/operator/manifest.go @@ -48,6 +48,7 @@ func (oper *Operator) ManifestExists(ctx context.Context, params *ManifestExists } var manifest descr.Manifest + manifests := make([]descr.Manifest, 0) var exists bool if stringLikeSHA256Digest(params.Reference) { digest := fmt.Sprintf("%s:%s", sha256prefix, params.Reference) @@ -59,13 +60,14 @@ func (oper *Operator) ManifestExists(ctx context.Context, params *ManifestExists return res, http.StatusNotFound, err } } else { - exists, manifest, err = oper.mdb.GetManifestByReference(ctx, params.Name, params.Reference) + exists, manifests, err = oper.mdb.GetManifestsByReference(ctx, params.Name, params.Reference) if err != nil { return res, http.StatusInternalServerError, err } if !exists { return res, http.StatusNotFound, err } + manifest = manifests[0] // TODO: tmp } digest := auxoci.SHA256DigestFromString(manifest.Payload) @@ -169,14 +171,17 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams incomingManifest.MediaType = params.ContentType } - manifestExists, existengManifestDescr, err := oper.mdb.GetManifestByReference(ctx, params.Name, params.Reference) + name := params.Name + reference := params.Reference + arch := incomingManifest.Subject.Platform.Architecture + os := incomingManifest.Subject.Platform.OS + variant := incomingManifest.Subject.Platform.Variant + + manifestExists, existengManifestDescr, err := oper.mdb.GetManifestsByReferenceArchitecture(ctx, name, reference, arch, os, variant) if err != nil { return res, http.StatusInternalServerError, err } - name := params.Name - reference := params.Reference - incomingManifestDescr, incomingLayerDescrs, err := descrsFromManifest(name, reference, incomingManifest, incomingManifestBytes) // Always check layer files for availability var blobError error @@ -297,23 +302,33 @@ func (oper *Operator) GetManifest(ctx context.Context, params *GetManifestParams if !exists { return res, http.StatusNotFound, err } + + manifestDigest := auxoci.SHA256DigestFromString(manifestDescr.Payload) + res.DockerContentDigest = manifestDigest.String() + + res.ContentLength = strconv.FormatInt(int64(len(manifestDescr.Payload)), 10) + res.ContentType = manifestDescr.ContentType + res.Payload = manifestDescr.Payload + } else { - exists, manifestDescr, err = oper.mdb.GetManifestByReference(ctx, params.Name, params.Reference) + exists, manifestDescrs, err := oper.mdb.GetManifestsByReference(ctx, params.Name, params.Reference) if err != nil { return res, http.StatusInternalServerError, err } if !exists { return res, http.StatusNotFound, err } + index, indexBytes, err := indexFromManigestDescrs(manifestDescrs) + if err != nil { + return res, http.StatusInternalServerError, err + } + indexDigest := auxoci.SHA256DigestFromString(indexBytes) + res.DockerContentDigest = indexDigest.String() + + res.ContentLength = strconv.FormatInt(int64(len(indexBytes)), 10) + res.ContentType = index.MediaType + res.Payload = string(indexBytes) } - - manifestDigest := auxoci.SHA256DigestFromString(manifestDescr.Payload) - res.DockerContentDigest = manifestDigest.String() - - res.ContentLength = strconv.FormatInt(int64(len(manifestDescr.Payload)), 10) - res.ContentType = manifestDescr.ContentType - res.Payload = manifestDescr.Payload - return res, http.StatusOK, err } @@ -352,9 +367,13 @@ func (oper *Operator) DeleteManifest(ctx context.Context, params *DeleteManifest return res, http.StatusNotFound, err } reference = manifestDescr.Reference + err = oper.deleteManifestObjects(ctx, params.Name, reference) + if err != nil { + return res, http.StatusInternalServerError, err + } } else { // Check manifest by name and reference - exists, manifestDescr, err = oper.mdb.GetManifestByReference(ctx, params.Name, params.Reference) + exists, manifestDescrs, err := oper.mdb.GetManifestsByReference(ctx, params.Name, params.Reference) if err != nil { return res, http.StatusInternalServerError, err } @@ -362,12 +381,15 @@ func (oper *Operator) DeleteManifest(ctx context.Context, params *DeleteManifest return res, http.StatusNotFound, err } reference = params.Reference + for _, manifestDescr := range manifestDescrs { + reference = manifestDescr.Reference + err = oper.deleteManifestObjects(ctx, params.Name, reference) + if err != nil { + return res, http.StatusInternalServerError, err + } + } } // Get blobs associated with the name - err = oper.deleteManifestObjects(ctx, params.Name, reference) - if err != nil { - return res, http.StatusInternalServerError, err - } return res, http.StatusAccepted, err } diff --git a/app/operator/ociaux.go b/app/operator/ociaux.go index a9ff8bc..85bd8a0 100644 --- a/app/operator/ociaux.go +++ b/app/operator/ociaux.go @@ -10,6 +10,9 @@ package operator import ( + "encoding/json" + + "mstore/pkg/auxoci" "mstore/pkg/auxtool" "mstore/pkg/auxuuid" "mstore/pkg/descr" @@ -18,6 +21,42 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) +func indexFromManigestDescrs(manifestDescrs []descr.Manifest) (ocispec.Index, string, error) { + var err error + var payload string + index := ocispec.Index{ + MediaType: ocispec.MediaTypeImageIndex, + Manifests: make([]ocispec.Descriptor, 0), + } + index.Versioned.SchemaVersion = 2 + for _, manifestDescr := range manifestDescrs { + var ociManifest ocispec.Manifest + + ociManifest.Subject = &ocispec.Descriptor{} + ociManifest.Subject.Platform = &ocispec.Platform{} + ociManifest.Config = ocispec.Descriptor{} + ociManifest.Config.Platform = &ocispec.Platform{} + + err = json.Unmarshal([]byte(manifestDescr.Payload), &ociManifest) + if err != nil { + return index, payload, err + } + descriptor := ocispec.Descriptor{ + MediaType: ocispec.MediaTypeImageManifest, + Digest: auxoci.SHA256DigestFromString(manifestDescr.Payload), + Size: int64(len(manifestDescr.Payload)), + Platform: ociManifest.Subject.Platform, + } + index.Manifests = append(index.Manifests, descriptor) + } + indexBytes, err := json.Marshal(index) + if err != nil { + return index, payload, err + } + payload = string(indexBytes) + return index, payload, err +} + func descrsFromManifest(name, reference string, manifest *ocispec.Manifest, rawManifest []byte) (descr.Manifest, []descr.Blob, error) { var err error manifestDescr := descr.Manifest{} diff --git a/pkg/auxoci/ociaux.go b/pkg/auxoci/ociaux.go index 95d71b1..deb51db 100644 --- a/pkg/auxoci/ociaux.go +++ b/pkg/auxoci/ociaux.go @@ -19,6 +19,11 @@ import ( func ParseOCIManifest(rawManifest []byte) (*ocispec.Manifest, error) { manifest := &ocispec.Manifest{} + manifest.Subject = &ocispec.Descriptor{} + manifest.Subject.Platform = &ocispec.Platform{} + manifest.Config = ocispec.Descriptor{} + manifest.Config.Platform = &ocispec.Platform{} + err := json.Unmarshal(rawManifest, &manifest) if err != nil { err = fmt.Errorf("Manifest parsing error: %v", err) diff --git a/pkg/descr/manifest.go b/pkg/descr/manifest.go index 6019645..a7daf94 100644 --- a/pkg/descr/manifest.go +++ b/pkg/descr/manifest.go @@ -10,16 +10,19 @@ package descr type Manifest struct { - ID string `db:"id" json:"id"` - Name string `db:"name" json:"name"` - Reference string `db:"reference" json:"reference"` - ContentType string `db:"contentType" json:"contentType"` - Payload string `db:"payload" json:"-"` - Digest string `db:"digest" json:"digest"` - CreatedAt string `db:"created_at" json:"createdAt"` - UpdatedAt string `db:"updated_at" json:"updatedAt"` - CreatedBy string `db:"created_by" json:"createdBy,omitempty"` - UpdatedBy string `db:"updated_by" json:"updatedBy,omitempty"` + ID string `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Reference string `db:"reference" json:"reference"` + ContentType string `db:"contentType" json:"contentType"` + Payload string `db:"payload" json:"-"` + Digest string `db:"digest" json:"digest"` + CreatedAt string `db:"created_at" json:"createdAt"` + UpdatedAt string `db:"updated_at" json:"updatedAt"` + CreatedBy string `db:"created_by" json:"createdBy,omitempty"` + UpdatedBy string `db:"updated_by" json:"updatedBy,omitempty"` + Architecture string `db:"architecture" json:"architecture,omitempty"` + OS string `db:"os" json:"os,omitempty"` + Variant string `db:"variant" json:"variant,omitempty"` } type Tags struct {