return index on get magifest

This commit is contained in:
2026-02-23 18:38:45 +02:00
parent 96b24c6b63
commit 5ec5592a13
8 changed files with 156 additions and 61 deletions
+2 -2
View File
@@ -33,9 +33,9 @@ func TestFile(t *testing.T) {
err = db.InitDatabase() err = db.InitDatabase()
require.NoError(t, err) require.NoError(t, err)
id := uuid.NewUUID() id := auxuuid.NewUUID()
timenow := auxtool.TimeNow() timenow := auxtool.TimeNow()
creator := uuid.NewUUID() creator := auxuuid.NewUUID()
collection := "foo" collection := "foo"
newFile := &descr.File{ newFile := &descr.File{
ID: id, ID: id,
+3 -3
View File
@@ -34,10 +34,10 @@ func TestGrant(t *testing.T) {
err = db.InitDatabase() err = db.InitDatabase()
require.NoError(t, err) require.NoError(t, err)
id := uuid.NewUUID() id := auxuuid.NewUUID()
accountID := uuid.NewUUID() accountID := auxuuid.NewUUID()
timenow := auxtool.TimeNow() timenow := auxtool.TimeNow()
creator := uuid.NewUUID() creator := auxuuid.NewUUID()
newGrant := &descr.Grant{ newGrant := &descr.Grant{
ID: id, ID: id,
AccountID: accountID, AccountID: accountID,
+39 -16
View File
@@ -19,12 +19,13 @@ func (db *Database) InsertManifest(ctx context.Context, manifest *descr.Manifest
var err error var err error
var request string var request string
request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest, request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest,
created_at, updated_at, created_by, updated_by) created_at, updated_at, created_by, updated_by, architecture, os, variant)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)` 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, _, err = db.db.Exec(request, manifest.ID, manifest.Name, manifest.Reference,
manifest.ContentType, manifest.Payload, manifest.Digest, manifest.ContentType, manifest.Payload, manifest.Digest,
manifest.CreatedAt, manifest.UpdatedAt, manifest.CreatedAt, manifest.UpdatedAt,
manifest.CreatedBy, manifest.UpdatedBy) manifest.CreatedBy, manifest.UpdatedBy,
manifest.Architecture, manifest.OS, manifest.Variant)
if err != nil { if err != nil {
return err return err
} }
@@ -39,12 +40,14 @@ func (db *Database) InsertManifests(ctx context.Context, manifests []*descr.Mani
for _, manifest := range manifests { for _, manifest := range manifests {
var request string var request string
request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest, request = `INSERT INTO manifests(id, name, reference, contentType, payload, digest,
created_at, updated_at, created_by, updated_by) created_at, updated_at, created_by, updated_by,
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)` 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, _, err = tx.Exec(request, manifest.ID, manifest.Name, manifest.Reference,
manifest.ContentType, manifest.Payload, manifest.Digest, manifest.ContentType, manifest.Payload, manifest.Digest,
manifest.CreatedAt, manifest.UpdatedAt, manifest.CreatedAt, manifest.UpdatedAt,
manifest.CreatedBy, manifest.UpdatedBy) manifest.CreatedBy, manifest.UpdatedBy,
manifest.Architecture, manifest.OS, manifest.Variant)
if err != nil { if err != nil {
return err return err
} }
@@ -62,9 +65,10 @@ func (db *Database) UpdateManifest(ctx context.Context, manifest *descr.Manifest
var request string var request string
// Manifest // Manifest
request = `UPDATE manifests SET contentType = $1, payload = $2, digest = $3, updated_at = $4 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, _, 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 { if err != nil {
return err return err
} }
@@ -80,12 +84,13 @@ func (db *Database) InsertManifestWithLayers(ctx context.Context, manifest *desc
// Manifest // Manifest
request = ` request = `
INSERT INTO manifests(id, name, reference, contentType, payload, digest, INSERT INTO manifests(id, name, reference, contentType, payload, digest,
created_at, updated_at, created_by, updated_by) created_at, updated_at, created_by, updated_by, architecture, os, variant)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);` VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);`
_, err = tx.Exec(request, manifest.ID, manifest.Name, manifest.Reference, _, err = tx.Exec(request, manifest.ID, manifest.Name, manifest.Reference,
manifest.ContentType, manifest.Payload, manifest.Digest, manifest.ContentType, manifest.Payload, manifest.Digest,
manifest.CreatedAt, manifest.UpdatedAt, manifest.CreatedAt, manifest.UpdatedAt,
manifest.CreatedBy, manifest.UpdatedBy) manifest.CreatedBy, manifest.UpdatedBy,
manifest.Architecture, manifest.OS, manifest.Variant)
if err != nil { if err != nil {
return err return err
} }
@@ -124,10 +129,11 @@ func (db *Database) UpdateManifestWithBlobs(ctx context.Context, manifest *descr
// Manifest // Manifest
request = `UPDATE manifests SET contentType = $1, payload = $2, digest = $3, updated_at = $4, updated_by = $5 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, _, err = tx.Exec(request, manifest.ContentType, manifest.Payload, manifest.Digest,
manifest.UpdatedAt, manifest.UpdatedBy, manifest.UpdatedAt, manifest.UpdatedBy,
manifest.Name, manifest.Reference) manifest.Name, manifest.Reference,
manifest.Architecture, manifest.OS, manifest.Variant)
if err != nil { if err != nil {
return err return err
} }
@@ -202,20 +208,37 @@ func (db *Database) GetManifestByDigest(ctx context.Context, name, digest string
return exists, manifest, err 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 var err error
manifest := descr.Manifest{}
exists := false exists := false
manifests := make([]descr.Manifest, 0) manifests := make([]descr.Manifest, 0)
request := `SELECT * FROM manifests WHERE name = $1 AND reference = $2 LIMIT 1` request := `SELECT * FROM manifests WHERE name = $1 AND reference = $2 LIMIT 1`
err = db.db.Select(&manifests, request, name, reference) err = db.db.Select(&manifests, request, name, reference)
if err != nil { if err != nil {
return exists, manifest, err return exists, manifests, err
} }
if len(manifests) > 0 { if len(manifests) > 0 {
exists = true 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] manifest = manifests[0]
exists = true
} }
return exists, manifest, err return exists, manifest, err
} }
+14 -11
View File
@@ -27,19 +27,22 @@ const schema = `
--- DROP TABLE IF EXISTS manifests; --- DROP TABLE IF EXISTS manifests;
CREATE TABLE IF NOT EXISTS manifests ( CREATE TABLE IF NOT EXISTS manifests (
id VARCHAR(255) NOT NULL, id VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
reference VARCHAR(255) NOT NULL, reference VARCHAR(255) NOT NULL,
digest VARCHAR(1024) NOT NULL, digest VARCHAR(1024) NOT NULL,
contentType VARCHAR(255) NOT NULL, contentType VARCHAR(255) NOT NULL,
payload VARCHAR(4096) NOT NULL, payload VARCHAR(4096) NOT NULL,
created_at VARCHAR(255) NOT NULL, created_at VARCHAR(255) NOT NULL,
updated_at VARCHAR(255) NOT NULL, updated_at VARCHAR(255) NOT NULL,
created_by VARCHAR(255) NOT NULL, created_by VARCHAR(255) NOT NULL,
updated_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 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 ( CREATE TABLE IF NOT EXISTS blobs (
id VARCHAR(255) NOT NULL, id VARCHAR(255) NOT NULL,
+41 -19
View File
@@ -48,6 +48,7 @@ func (oper *Operator) ManifestExists(ctx context.Context, params *ManifestExists
} }
var manifest descr.Manifest var manifest descr.Manifest
manifests := make([]descr.Manifest, 0)
var exists bool var exists bool
if stringLikeSHA256Digest(params.Reference) { if stringLikeSHA256Digest(params.Reference) {
digest := fmt.Sprintf("%s:%s", sha256prefix, 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 return res, http.StatusNotFound, err
} }
} else { } 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 { if err != nil {
return res, http.StatusInternalServerError, err return res, http.StatusInternalServerError, err
} }
if !exists { if !exists {
return res, http.StatusNotFound, err return res, http.StatusNotFound, err
} }
manifest = manifests[0] // TODO: tmp
} }
digest := auxoci.SHA256DigestFromString(manifest.Payload) digest := auxoci.SHA256DigestFromString(manifest.Payload)
@@ -169,14 +171,17 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams
incomingManifest.MediaType = params.ContentType 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 { if err != nil {
return res, http.StatusInternalServerError, err return res, http.StatusInternalServerError, err
} }
name := params.Name
reference := params.Reference
incomingManifestDescr, incomingLayerDescrs, err := descrsFromManifest(name, reference, incomingManifest, incomingManifestBytes) incomingManifestDescr, incomingLayerDescrs, err := descrsFromManifest(name, reference, incomingManifest, incomingManifestBytes)
// Always check layer files for availability // Always check layer files for availability
var blobError error var blobError error
@@ -297,23 +302,33 @@ func (oper *Operator) GetManifest(ctx context.Context, params *GetManifestParams
if !exists { if !exists {
return res, http.StatusNotFound, err 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 { } 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 { if err != nil {
return res, http.StatusInternalServerError, err return res, http.StatusInternalServerError, err
} }
if !exists { if !exists {
return res, http.StatusNotFound, err 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 return res, http.StatusOK, err
} }
@@ -352,9 +367,13 @@ func (oper *Operator) DeleteManifest(ctx context.Context, params *DeleteManifest
return res, http.StatusNotFound, err return res, http.StatusNotFound, err
} }
reference = manifestDescr.Reference reference = manifestDescr.Reference
err = oper.deleteManifestObjects(ctx, params.Name, reference)
if err != nil {
return res, http.StatusInternalServerError, err
}
} else { } else {
// Check manifest by name and reference // 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 { if err != nil {
return res, http.StatusInternalServerError, err return res, http.StatusInternalServerError, err
} }
@@ -362,12 +381,15 @@ func (oper *Operator) DeleteManifest(ctx context.Context, params *DeleteManifest
return res, http.StatusNotFound, err return res, http.StatusNotFound, err
} }
reference = params.Reference 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 // 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 return res, http.StatusAccepted, err
} }
+39
View File
@@ -10,6 +10,9 @@
package operator package operator
import ( import (
"encoding/json"
"mstore/pkg/auxoci"
"mstore/pkg/auxtool" "mstore/pkg/auxtool"
"mstore/pkg/auxuuid" "mstore/pkg/auxuuid"
"mstore/pkg/descr" "mstore/pkg/descr"
@@ -18,6 +21,42 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1" 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) { func descrsFromManifest(name, reference string, manifest *ocispec.Manifest, rawManifest []byte) (descr.Manifest, []descr.Blob, error) {
var err error var err error
manifestDescr := descr.Manifest{} manifestDescr := descr.Manifest{}
+5
View File
@@ -19,6 +19,11 @@ import (
func ParseOCIManifest(rawManifest []byte) (*ocispec.Manifest, error) { func ParseOCIManifest(rawManifest []byte) (*ocispec.Manifest, error) {
manifest := &ocispec.Manifest{} 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) err := json.Unmarshal(rawManifest, &manifest)
if err != nil { if err != nil {
err = fmt.Errorf("Manifest parsing error: %v", err) err = fmt.Errorf("Manifest parsing error: %v", err)
+13 -10
View File
@@ -10,16 +10,19 @@
package descr package descr
type Manifest struct { type Manifest struct {
ID string `db:"id" json:"id"` ID string `db:"id" json:"id"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Reference string `db:"reference" json:"reference"` Reference string `db:"reference" json:"reference"`
ContentType string `db:"contentType" json:"contentType"` ContentType string `db:"contentType" json:"contentType"`
Payload string `db:"payload" json:"-"` Payload string `db:"payload" json:"-"`
Digest string `db:"digest" json:"digest"` Digest string `db:"digest" json:"digest"`
CreatedAt string `db:"created_at" json:"createdAt"` CreatedAt string `db:"created_at" json:"createdAt"`
UpdatedAt string `db:"updated_at" json:"updatedAt"` UpdatedAt string `db:"updated_at" json:"updatedAt"`
CreatedBy string `db:"created_by" json:"createdBy,omitempty"` CreatedBy string `db:"created_by" json:"createdBy,omitempty"`
UpdatedBy string `db:"updated_by" json:"updatedBy,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 { type Tags struct {