mirror of
https://github.com/goharbor/harbor
synced 2025-04-16 22:01:27 +00:00
feat: add the cnai model processor for artifact
Signed-off-by: chlins <chlins.zhang@gmail.com>
This commit is contained in:
parent
3dbfd4229b
commit
cadd66936b
BIN
icons/model.png
Normal file
BIN
icons/model.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
|
@ -83,7 +83,7 @@ func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Ar
|
|||
default:
|
||||
return fmt.Errorf("unsupported manifest media type: %s", artifact.ManifestMediaType)
|
||||
}
|
||||
return processor.Get(artifact.MediaType).AbstractMetadata(ctx, artifact, content)
|
||||
return processor.Get(artifact.ArtifactType).AbstractMetadata(ctx, artifact, content)
|
||||
}
|
||||
|
||||
// the artifact is enveloped by docker manifest v1
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/goharbor/harbor/src/controller/artifact/processor/chart"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/cnab"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/image"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/model"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/sbom"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/wasm"
|
||||
"github.com/goharbor/harbor/src/controller/event/metadata"
|
||||
|
@ -44,7 +45,7 @@ import (
|
|||
accessorymodel "github.com/goharbor/harbor/src/pkg/accessory/model"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/artifactrash"
|
||||
"github.com/goharbor/harbor/src/pkg/artifactrash/model"
|
||||
trashmodel "github.com/goharbor/harbor/src/pkg/artifactrash/model"
|
||||
"github.com/goharbor/harbor/src/pkg/blob"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match"
|
||||
"github.com/goharbor/harbor/src/pkg/immutable/match/rule"
|
||||
|
@ -78,6 +79,7 @@ var (
|
|||
cnab.ArtifactTypeCNAB: icon.DigestOfIconCNAB,
|
||||
wasm.ArtifactTypeWASM: icon.DigestOfIconWASM,
|
||||
sbom.ArtifactTypeSBOM: icon.DigestOfIconAccSBOM,
|
||||
model.ArtifactTypeModel: icon.DigestOfIconModel,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -219,7 +221,7 @@ func (c *controller) ensureArtifact(ctx context.Context, repository, digest stri
|
|||
}
|
||||
|
||||
// populate the artifact type
|
||||
artifact.Type = processor.Get(artifact.MediaType).GetArtifactType(ctx, artifact)
|
||||
artifact.Type = processor.Get(artifact.ArtifactType).GetArtifactType(ctx, artifact)
|
||||
|
||||
// create it
|
||||
// use orm.WithTransaction here to avoid the issue:
|
||||
|
@ -437,7 +439,7 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot, isAcces
|
|||
// use orm.WithTransaction here to avoid the issue:
|
||||
// https://www.postgresql.org/message-id/002e01c04da9%24a8f95c20%2425efe6c1%40lasting.ro
|
||||
if err = orm.WithTransaction(func(ctx context.Context) error {
|
||||
_, err = c.artrashMgr.Create(ctx, &model.ArtifactTrash{
|
||||
_, err = c.artrashMgr.Create(ctx, &trashmodel.ArtifactTrash{
|
||||
MediaType: art.MediaType,
|
||||
ManifestMediaType: art.ManifestMediaType,
|
||||
RepositoryName: art.RepositoryName,
|
||||
|
@ -593,7 +595,7 @@ func (c *controller) GetAddition(ctx context.Context, artifactID int64, addition
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return processor.Get(artifact.MediaType).AbstractAddition(ctx, artifact, addition)
|
||||
return processor.Get(artifact.ArtifactType).AbstractAddition(ctx, artifact, addition)
|
||||
}
|
||||
|
||||
func (c *controller) AddLabel(ctx context.Context, artifactID int64, labelID int64) (err error) {
|
||||
|
@ -751,7 +753,7 @@ func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
|||
}
|
||||
|
||||
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
|
||||
types := processor.Get(artifact.MediaType).ListAdditionTypes(ctx, &artifact.Artifact)
|
||||
types := processor.Get(artifact.ArtifactType).ListAdditionTypes(ctx, &artifact.Artifact)
|
||||
if len(types) > 0 {
|
||||
version := lib.GetAPIVersion(ctx)
|
||||
for _, t := range types {
|
||||
|
|
114
src/controller/artifact/processor/model/model.go
Normal file
114
src/controller/artifact/processor/model/model.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
ps "github.com/goharbor/harbor/src/controller/artifact/processor"
|
||||
"github.com/goharbor/harbor/src/controller/artifact/processor/base"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
)
|
||||
|
||||
// const definitions
|
||||
const (
|
||||
// ArtifactTypeModel defines the artifact type for AI models
|
||||
ArtifactTypeModel = "MODEL"
|
||||
AdditionTypeReadme = "README.MD"
|
||||
|
||||
// TODO: import from cnai model spec
|
||||
artifactType = "application/vnd.cnai.model.manifest.v1+json"
|
||||
)
|
||||
|
||||
func init() {
|
||||
pc := &processor{
|
||||
ManifestProcessor: base.NewManifestProcessor(),
|
||||
}
|
||||
if err := ps.Register(pc, artifactType); err != nil {
|
||||
log.Errorf("failed to register processor for artifact type %s: %v", artifactType, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type processor struct {
|
||||
*base.ManifestProcessor
|
||||
}
|
||||
|
||||
func (p *processor) AbstractAddition(_ context.Context, artifact *artifact.Artifact, addition string) (*ps.Addition, error) {
|
||||
if addition != AdditionTypeReadme {
|
||||
return nil, errors.New(nil).WithCode(errors.BadRequestCode).
|
||||
WithMessagef("addition %s isn't supported for %s", addition, ArtifactTypeModel)
|
||||
}
|
||||
|
||||
m, _, err := p.RegCli.PullManifest(artifact.RepositoryName, artifact.Digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, payload, err := m.Payload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifest := &v1.Manifest{}
|
||||
if err := json.Unmarshal(payload, manifest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, layer := range manifest.Layers {
|
||||
layerDgst := layer.Digest.String()
|
||||
// currently, we only handle readme addition for model artifact.
|
||||
if layerDgst != manifest.Config.Digest.String() &&
|
||||
(layer.Annotations != nil && layer.Annotations["org.cnai.model.readme"] == "true") {
|
||||
_, blob, err := p.RegCli.PullBlob(artifact.RepositoryName, layerDgst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer blob.Close()
|
||||
content, err := io.ReadAll(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var additionContent []byte
|
||||
var additionContentType string
|
||||
|
||||
switch addition {
|
||||
case AdditionTypeReadme:
|
||||
additionContent = []byte(content)
|
||||
additionContentType = "text/markdown; charset=utf-8"
|
||||
}
|
||||
|
||||
return &ps.Addition{
|
||||
Content: additionContent,
|
||||
ContentType: additionContentType,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *processor) GetArtifactType(_ context.Context, _ *artifact.Artifact) string {
|
||||
return ArtifactTypeModel
|
||||
}
|
||||
|
||||
func (p *processor) ListAdditionTypes(_ context.Context, _ *artifact.Artifact) []string {
|
||||
return []string{AdditionTypeReadme}
|
||||
}
|
|
@ -77,6 +77,10 @@ var (
|
|||
path: "./icons/default.png",
|
||||
resize: true,
|
||||
},
|
||||
icon.DigestOfIconModel: {
|
||||
path: "./icons/model.png",
|
||||
resize: true,
|
||||
},
|
||||
}
|
||||
// Ctl is a global icon controller instance
|
||||
Ctl = NewController()
|
||||
|
|
|
@ -28,4 +28,5 @@ const (
|
|||
DigestOfIconAccNotation = "sha256:3ac706e102bbe9362b400aa162df58135d35e66b9c3bee2165de92022d25fe34"
|
||||
DigestOfIconAccNydus = "sha256:dfcb6617cd9c144358dc1b305b87bbe34f0b619f1e329116e6aee2e41f2e34cf"
|
||||
DigestOfIconAccSBOM = "sha256:c19f80c357cd7e90d2a01b9ae3e2eb62ce447a2662bb590a19177d72d550bdae"
|
||||
DigestOfIconModel = "sha256:9f51c0a8800e98c84952264755c956dba448f2d62112eff5c5a4ef88cd460d1e"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user