harbor/src/pkg/artifact/model.go

205 lines
6.9 KiB
Go

// 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 artifact
import (
"encoding/json"
"time"
"github.com/docker/distribution/manifest/manifestlist"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/artifact/dao"
"github.com/goharbor/harbor/src/server/v2.0/models"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
// Artifact is the abstract object managed by Harbor. It hides the
// underlying concrete detail and provides an unified artifact view
// for all users.
type Artifact struct {
ID int64 `json:"id"`
Type string `json:"type"` // image, chart, etc
MediaType string `json:"media_type"` // the media type of artifact. Mostly, it's the value of `manifest.config.mediatype`
ManifestMediaType string `json:"manifest_media_type"` // the media type of manifest/index
ProjectID int64 `json:"project_id"`
RepositoryID int64 `json:"repository_id"`
RepositoryName string `json:"repository_name"`
Digest string `json:"digest"`
Size int64 `json:"size"`
Icon string `json:"icon"`
PushTime time.Time `json:"push_time"`
PullTime time.Time `json:"pull_time"`
ExtraAttrs map[string]interface{} `json:"extra_attrs"` // only contains the simple attributes specific for the different artifact type, most of them should come from the config layer
Annotations map[string]string `json:"annotations"`
References []*Reference `json:"references"` // child artifacts referenced by the parent artifact if the artifact is an index
}
// IsImageIndex returns true when artifact is image index
func (a *Artifact) IsImageIndex() bool {
return a.ManifestMediaType == v1.MediaTypeImageIndex ||
a.ManifestMediaType == manifestlist.MediaTypeManifestList
}
// From converts the database level artifact to the business level object
func (a *Artifact) From(art *dao.Artifact) {
a.ID = art.ID
a.Type = art.Type
a.MediaType = art.MediaType
a.ManifestMediaType = art.ManifestMediaType
a.ProjectID = art.ProjectID
a.RepositoryID = art.RepositoryID
a.RepositoryName = art.RepositoryName
a.Digest = art.Digest
a.Size = art.Size
a.Icon = art.Icon
a.PushTime = art.PushTime
a.PullTime = art.PullTime
a.ExtraAttrs = map[string]interface{}{}
a.Annotations = map[string]string{}
if len(art.ExtraAttrs) > 0 {
if err := json.Unmarshal([]byte(art.ExtraAttrs), &a.ExtraAttrs); err != nil {
log.Errorf("failed to unmarshal the extra attrs of artifact %d: %v", art.ID, err)
}
}
if len(art.Annotations) > 0 {
if err := json.Unmarshal([]byte(art.Annotations), &a.Annotations); err != nil {
log.Errorf("failed to unmarshal the annotations of artifact %d: %v", art.ID, err)
}
}
}
// To converts the artifact to the database level object
func (a *Artifact) To() *dao.Artifact {
art := &dao.Artifact{
ID: a.ID,
Type: a.Type,
MediaType: a.MediaType,
ManifestMediaType: a.ManifestMediaType,
ProjectID: a.ProjectID,
RepositoryID: a.RepositoryID,
RepositoryName: a.RepositoryName,
Digest: a.Digest,
Size: a.Size,
Icon: a.Icon,
PushTime: a.PushTime,
PullTime: a.PullTime,
}
if len(a.ExtraAttrs) > 0 {
attrs, err := json.Marshal(a.ExtraAttrs)
if err != nil {
log.Errorf("failed to marshal the extra attrs of artifact %d: %v", a.ID, err)
}
art.ExtraAttrs = string(attrs)
}
if len(a.Annotations) > 0 {
annotations, err := json.Marshal(a.Annotations)
if err != nil {
log.Errorf("failed to marshal the annotations of artifact %d: %v", a.ID, err)
}
art.Annotations = string(annotations)
}
return art
}
// Reference records the child artifact referenced by parent artifact
type Reference struct {
ID int64 `json:"id"`
ParentID int64 `json:"parent_id"`
ChildID int64 `json:"child_id"`
ChildDigest string `json:"child_digest"`
Platform *v1.Platform
URLs []string `json:"urls"`
Annotations map[string]string `json:"annotations"`
}
// From converts the data level reference to business level
func (r *Reference) From(ref *dao.ArtifactReference) {
r.ID = ref.ID
r.ParentID = ref.ParentID
r.ChildID = ref.ChildID
r.ChildDigest = ref.ChildDigest
if len(ref.Platform) > 0 {
r.Platform = &v1.Platform{}
if err := json.Unmarshal([]byte(ref.Platform), r.Platform); err != nil {
log.Errorf("failed to unmarshal the platform of reference: %v", err)
}
}
if len(ref.URLs) > 0 {
r.URLs = []string{}
if err := json.Unmarshal([]byte(ref.URLs), &r.URLs); err != nil {
log.Errorf("failed to unmarshal the URLs of reference: %v", err)
}
}
if len(ref.Annotations) > 0 {
r.Annotations = map[string]string{}
if err := json.Unmarshal([]byte(ref.Annotations), &r.Annotations); err != nil {
log.Errorf("failed to unmarshal the annotations of reference: %v", err)
}
}
}
// To converts the reference to data level object
func (r *Reference) To() *dao.ArtifactReference {
ref := &dao.ArtifactReference{
ID: r.ID,
ParentID: r.ParentID,
ChildID: r.ChildID,
ChildDigest: r.ChildDigest,
}
if r.Platform != nil {
platform, err := json.Marshal(r.Platform)
if err != nil {
log.Errorf("failed to marshal the platform of reference: %v", err)
}
ref.Platform = string(platform)
}
if len(r.URLs) > 0 {
urls, err := json.Marshal(r.URLs)
if err != nil {
log.Errorf("failed to marshal the URLs of reference: %v", err)
}
ref.URLs = string(urls)
}
if len(r.Annotations) > 0 {
annotations, err := json.Marshal(r.Annotations)
if err != nil {
log.Errorf("failed to marshal the annotations of reference: %v", err)
}
ref.Annotations = string(annotations)
}
return ref
}
// ToSwagger converts the reference to the swagger model
func (r *Reference) ToSwagger() *models.Reference {
ref := &models.Reference{
ChildDigest: r.ChildDigest,
ChildID: r.ChildID,
ParentID: r.ParentID,
Annotations: r.Annotations,
Urls: r.URLs,
}
if r.Platform != nil {
ref.Platform = &models.Platform{
Architecture: r.Platform.Architecture,
Os: r.Platform.OS,
OsFeatures: r.Platform.OSFeatures,
OsVersion: r.Platform.OSVersion,
Variant: r.Platform.Variant,
}
}
return ref
}