0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00
zot/pkg/meta/convert/convert.go
LaurentiuNiculae de90abd5dc
style(metadb): use type aliases for metadb types to be easier to read (#2043)
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
2024-02-14 09:08:08 -08:00

634 lines
17 KiB
Go

package convert
import (
"time"
godigest "github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"google.golang.org/protobuf/types/known/timestamppb"
"zotregistry.dev/zot/pkg/common"
proto_go "zotregistry.dev/zot/pkg/meta/proto/gen"
mTypes "zotregistry.dev/zot/pkg/meta/types"
)
func GetHistory(history []*proto_go.History) []ispec.History {
if history == nil {
return nil
}
results := make([]ispec.History, 0, len(history))
for _, his := range history {
results = append(results, ispec.History{
Created: ref(his.Created.AsTime()),
CreatedBy: deref(his.CreatedBy, ""),
Author: deref(his.Author, ""),
Comment: deref(his.Comment, ""),
EmptyLayer: deref(his.EmptyLayer, false),
})
}
return results
}
func GetImageArtifactType(imageMeta *proto_go.ImageMeta) string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
manifestArtifactType := deref(imageMeta.Manifests[0].Manifest.ArtifactType, "")
if manifestArtifactType != "" {
return manifestArtifactType
}
return imageMeta.Manifests[0].Manifest.Config.MediaType
case ispec.MediaTypeImageIndex:
return deref(imageMeta.Index.Index.ArtifactType, "")
default:
return ""
}
}
func GetImageManifestSize(imageMeta *proto_go.ImageMeta) int64 {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Size
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Size
default:
return 0
}
}
func GetImageDigest(imageMeta *proto_go.ImageMeta) godigest.Digest {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return godigest.Digest(imageMeta.Manifests[0].Digest)
case ispec.MediaTypeImageIndex:
return godigest.Digest(imageMeta.Index.Digest)
default:
return ""
}
}
func GetImageDigestStr(imageMeta *proto_go.ImageMeta) string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Digest
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Digest
default:
return ""
}
}
func GetImageAnnotations(imageMeta *proto_go.ImageMeta) map[string]string {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
return imageMeta.Manifests[0].Manifest.Annotations
case ispec.MediaTypeImageIndex:
return imageMeta.Index.Index.Annotations
default:
return map[string]string{}
}
}
func GetImageSubject(imageMeta *proto_go.ImageMeta) *ispec.Descriptor {
switch imageMeta.MediaType {
case ispec.MediaTypeImageManifest:
if imageMeta.Manifests[0].Manifest.Subject == nil {
return nil
}
return GetDescriptorRef(imageMeta.Manifests[0].Manifest.Subject)
case ispec.MediaTypeImageIndex:
if imageMeta.Index.Index.Subject == nil {
return nil
}
return GetDescriptorRef(imageMeta.Index.Index.Subject)
default:
return nil
}
}
func GetDescriptorRef(descriptor *proto_go.Descriptor) *ispec.Descriptor {
if descriptor == nil {
return nil
}
platform := GetPlatformRef(descriptor.Platform)
return &ispec.Descriptor{
MediaType: descriptor.MediaType,
Digest: godigest.Digest(descriptor.Digest),
Size: descriptor.Size,
URLs: descriptor.URLs,
Data: descriptor.Data,
Platform: platform,
ArtifactType: deref(descriptor.ArtifactType, ""),
Annotations: descriptor.Annotations,
}
}
func GetPlatform(platform *proto_go.Platform) ispec.Platform {
if platform == nil {
return ispec.Platform{}
}
return ispec.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: deref(platform.OSVersion, ""),
OSFeatures: platform.OSFeatures,
Variant: deref(platform.Variant, ""),
}
}
func GetPlatformRef(platform *proto_go.Platform) *ispec.Platform {
if platform == nil {
return nil
}
return &ispec.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: deref(platform.OSVersion, ""),
OSFeatures: platform.OSFeatures,
Variant: deref(platform.Variant, ""),
}
}
func GetLayers(descriptors []*proto_go.Descriptor) []ispec.Descriptor {
results := make([]ispec.Descriptor, 0, len(descriptors))
for _, desc := range descriptors {
results = append(results, ispec.Descriptor{
MediaType: desc.MediaType,
Digest: godigest.Digest(desc.Digest),
Size: desc.Size,
})
}
return results
}
func GetSubject(subj *proto_go.Descriptor) *ispec.Descriptor {
if subj == nil {
return nil
}
return &ispec.Descriptor{
MediaType: subj.MediaType,
Digest: godigest.Digest(subj.Digest),
Size: subj.Size,
}
}
func GetReferrers(refs map[string]*proto_go.ReferrersInfo) map[string][]mTypes.ReferrerInfo {
results := map[string][]mTypes.ReferrerInfo{}
for digest, ref := range refs {
referrers := []mTypes.ReferrerInfo{}
for _, dbRef := range ref.List {
referrers = append(referrers, mTypes.ReferrerInfo{
Digest: dbRef.Digest,
MediaType: dbRef.MediaType,
ArtifactType: dbRef.ArtifactType,
Size: int(dbRef.Size),
Annotations: dbRef.Annotations,
})
}
results[digest] = referrers
}
return results
}
func GetImageReferrers(refs *proto_go.ReferrersInfo) []mTypes.ReferrerInfo {
if refs == nil {
return []mTypes.ReferrerInfo{}
}
results := []mTypes.ReferrerInfo{}
for _, dbRef := range refs.List {
results = append(results, mTypes.ReferrerInfo{
Digest: dbRef.Digest,
MediaType: dbRef.MediaType,
ArtifactType: dbRef.ArtifactType,
Size: int(dbRef.Size),
Annotations: dbRef.Annotations,
})
}
return results
}
func GetSignatures(sigs map[string]*proto_go.ManifestSignatures) map[string]mTypes.ManifestSignatures {
results := map[string]mTypes.ManifestSignatures{}
for digest, dbSignatures := range sigs {
imageSignatures := mTypes.ManifestSignatures{}
for signatureName, signatureInfo := range dbSignatures.Map {
imageSignatures[signatureName] = GetSignaturesInfo(signatureInfo.List)
}
results[digest] = imageSignatures
}
return results
}
func GetImageSignatures(sigs *proto_go.ManifestSignatures) mTypes.ManifestSignatures {
if sigs == nil {
return mTypes.ManifestSignatures{}
}
results := mTypes.ManifestSignatures{}
for signatureName, signatureInfo := range sigs.Map {
results[signatureName] = GetSignaturesInfo(signatureInfo.List)
}
return results
}
func GetSignaturesInfo(sigsInfo []*proto_go.SignatureInfo) []mTypes.SignatureInfo {
results := []mTypes.SignatureInfo{}
for _, siginfo := range sigsInfo {
results = append(results, mTypes.SignatureInfo{
SignatureManifestDigest: siginfo.SignatureManifestDigest,
LayersInfo: GetLayersInfo(siginfo.LayersInfo),
})
}
return results
}
func GetLayersInfo(layersInfo []*proto_go.LayersInfo) []mTypes.LayerInfo {
results := []mTypes.LayerInfo{}
for _, layerInfo := range layersInfo {
date := time.Time{}
if layerInfo.Date != nil {
date = layerInfo.Date.AsTime()
}
results = append(results, mTypes.LayerInfo{
LayerDigest: layerInfo.LayerDigest,
LayerContent: layerInfo.LayerContent,
SignatureKey: layerInfo.SignatureKey,
Signer: layerInfo.Signer,
Date: date,
})
}
return results
}
func GetStatisticsMap(stats map[mTypes.ImageDigest]*proto_go.DescriptorStatistics,
) map[mTypes.ImageDigest]mTypes.DescriptorStatistics {
results := map[mTypes.ImageDigest]mTypes.DescriptorStatistics{}
for digest, stat := range stats {
results[digest] = mTypes.DescriptorStatistics{
DownloadCount: int(stat.DownloadCount),
LastPullTimestamp: stat.LastPullTimestamp.AsTime(),
PushTimestamp: stat.PushTimestamp.AsTime(),
PushedBy: stat.PushedBy,
}
}
return results
}
func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics {
if stats == nil {
return mTypes.DescriptorStatistics{}
}
return mTypes.DescriptorStatistics{
DownloadCount: int(stats.DownloadCount),
LastPullTimestamp: stats.LastPullTimestamp.AsTime(),
PushTimestamp: stats.PushTimestamp.AsTime(),
PushedBy: stats.PushedBy,
}
}
func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64,
digest godigest.Digest,
) mTypes.ImageMeta {
return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageManifest,
Digest: digest,
Size: size,
Manifests: []mTypes.ManifestMeta{
{
Digest: digest,
Size: size,
Config: configContent,
Manifest: manifestContent,
},
},
}
}
func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta {
return mTypes.ImageMeta{
MediaType: ispec.MediaTypeImageIndex,
Index: &indexContent,
Manifests: GetManifests(indexContent.Manifests),
Size: size,
Digest: digest,
}
}
func GetTags(tags map[mTypes.Tag]*proto_go.TagDescriptor) map[mTypes.Tag]mTypes.Descriptor {
resultMap := map[mTypes.Tag]mTypes.Descriptor{}
for tag, tagDescriptor := range tags {
resultMap[tag] = mTypes.Descriptor{
Digest: tagDescriptor.Digest,
MediaType: tagDescriptor.MediaType,
}
}
return resultMap
}
func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestMeta {
manifestList := []mTypes.ManifestMeta{}
for _, manifest := range descriptors {
manifestList = append(manifestList, mTypes.ManifestMeta{
Digest: manifest.Digest,
Size: manifest.Size,
})
}
return manifestList
}
func GetTime(time *timestamppb.Timestamp) *time.Time {
if time == nil {
return nil
}
return ref(time.AsTime())
}
func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta,
) mTypes.FullImageMeta {
if protoRepoMeta == nil {
return mTypes.FullImageMeta{}
}
imageMeta := GetImageMeta(protoImageMeta)
imageDigest := imageMeta.Digest.String()
return mTypes.FullImageMeta{
Repo: protoRepoMeta.Name,
Tag: tag,
MediaType: imageMeta.MediaType,
Digest: imageMeta.Digest,
Size: imageMeta.Size,
Index: imageMeta.Index,
Manifests: GetFullManifestData(protoRepoMeta, imageMeta.Manifests),
IsStarred: protoRepoMeta.IsStarred,
IsBookmarked: protoRepoMeta.IsBookmarked,
Referrers: GetImageReferrers(protoRepoMeta.Referrers[imageDigest]),
Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]),
Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]),
}
}
func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestMeta,
) []mTypes.FullManifestMeta {
if protoRepoMeta == nil {
return []mTypes.FullManifestMeta{}
}
results := []mTypes.FullManifestMeta{}
for i := range manifestData {
results = append(results, mTypes.FullManifestMeta{
ManifestMeta: manifestData[i],
Referrers: GetImageReferrers(protoRepoMeta.Referrers[manifestData[i].Digest.String()]),
Statistics: GetImageStatistics(protoRepoMeta.Statistics[manifestData[i].Digest.String()]),
Signatures: GetImageSignatures(protoRepoMeta.Signatures[manifestData[i].Digest.String()]),
})
}
return results
}
func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta {
if protoRepoMeta == nil {
return mTypes.RepoMeta{}
}
repoDownloads := int32(0)
for _, descriptor := range protoRepoMeta.Tags {
if statistic := protoRepoMeta.Statistics[descriptor.Digest]; statistic != nil {
repoDownloads += statistic.DownloadCount
}
}
return mTypes.RepoMeta{
Name: protoRepoMeta.Name,
Tags: GetTags(protoRepoMeta.Tags),
Rank: int(protoRepoMeta.Rank),
Size: protoRepoMeta.Size,
Platforms: GetPlatforms(protoRepoMeta.Platforms),
Vendors: protoRepoMeta.Vendors,
IsStarred: protoRepoMeta.IsStarred,
IsBookmarked: protoRepoMeta.IsBookmarked,
StarCount: int(protoRepoMeta.Stars),
DownloadCount: int(repoDownloads),
LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.LastUpdatedImage),
Statistics: GetStatisticsMap(protoRepoMeta.Statistics),
Signatures: GetSignatures(protoRepoMeta.Signatures),
Referrers: GetReferrers(protoRepoMeta.Referrers),
}
}
func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform {
result := []ispec.Platform{}
for i := range platforms {
result = append(result, GetPlatform(platforms[i]))
}
return result
}
func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform {
for _, newPlatform := range newPlatforms {
if !ContainsProtoPlatform(platforms, newPlatform) {
platforms = append(platforms, newPlatform)
}
}
return platforms
}
func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool {
for i := range platforms {
if platforms[i].OS == platform.OS && platforms[i].Architecture == platform.Architecture {
return true
}
}
return false
}
func AddVendors(vendors []string, newVendors []string) []string {
for _, newVendor := range newVendors {
if !common.Contains(vendors, newVendor) {
vendors = append(vendors, newVendor)
}
}
return vendors
}
func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage {
if protoLastUpdated == nil {
return nil
}
return &mTypes.LastUpdatedImage{
Descriptor: mTypes.Descriptor{
Digest: protoLastUpdated.Digest,
MediaType: protoLastUpdated.MediaType,
},
Tag: protoLastUpdated.Tag,
LastUpdated: GetTime(protoLastUpdated.LastUpdated),
}
}
func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta {
if dbImageMeta == nil {
return mTypes.ImageMeta{}
}
imageMeta := mTypes.ImageMeta{
MediaType: dbImageMeta.MediaType,
Size: GetImageManifestSize(dbImageMeta),
Digest: GetImageDigest(dbImageMeta),
}
if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
for _, manifest := range deref(dbImageMeta.Index, proto_go.IndexMeta{}).Index.Manifests {
manifests = append(manifests, ispec.Descriptor{
MediaType: manifest.MediaType,
Digest: godigest.Digest(manifest.Digest),
Size: manifest.Size,
})
}
imageMeta.Index = &ispec.Index{
Versioned: specs.Versioned{SchemaVersion: int(dbImageMeta.Index.Index.Versioned.GetSchemaVersion())},
MediaType: ispec.MediaTypeImageIndex,
Manifests: manifests,
Subject: GetImageSubject(dbImageMeta),
ArtifactType: GetImageArtifactType(dbImageMeta),
Annotations: GetImageAnnotations(dbImageMeta),
}
}
manifestDataList := make([]mTypes.ManifestMeta, 0, len(dbImageMeta.Manifests))
for _, manifest := range dbImageMeta.Manifests {
manifestDataList = append(manifestDataList, mTypes.ManifestMeta{
Size: manifest.Size,
Digest: godigest.Digest(manifest.Digest),
Manifest: ispec.Manifest{
Versioned: specs.Versioned{SchemaVersion: int(manifest.Manifest.Versioned.GetSchemaVersion())},
MediaType: deref(manifest.Manifest.MediaType, ""),
ArtifactType: deref(manifest.Manifest.ArtifactType, ""),
Config: ispec.Descriptor{
MediaType: manifest.Manifest.Config.MediaType,
Size: manifest.Manifest.Config.Size,
Digest: godigest.Digest(manifest.Manifest.Config.Digest),
},
Layers: GetLayers(manifest.Manifest.Layers),
Subject: GetSubject(manifest.Manifest.Subject),
Annotations: manifest.Manifest.Annotations,
},
Config: ispec.Image{
Created: GetTime(manifest.Config.Created),
Author: deref(manifest.Config.Author, ""),
Platform: GetPlatform(manifest.Config.Platform),
Config: ispec.ImageConfig{
User: manifest.Config.Config.User,
ExposedPorts: GetExposedPorts(manifest.Config.Config.ExposedPorts),
Env: manifest.Config.Config.Env,
Entrypoint: manifest.Config.Config.Entrypoint,
Cmd: manifest.Config.Config.Cmd,
Volumes: GetConfigVolumes(manifest.Config.Config.Volumes),
WorkingDir: deref(manifest.Config.Config.WorkingDir, ""),
Labels: manifest.Config.Config.Labels,
StopSignal: deref(manifest.Config.Config.StopSignal, ""),
},
RootFS: ispec.RootFS{
Type: manifest.Config.RootFS.Type,
DiffIDs: GetDiffIDs(manifest.Config.RootFS.DiffIDs),
},
History: GetHistory(manifest.Config.History),
},
})
}
imageMeta.Manifests = manifestDataList
return imageMeta
}
func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} {
if exposedPorts == nil {
return nil
}
result := map[string]struct{}{}
for key := range exposedPorts {
result[key] = struct{}{}
}
return result
}
func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} {
if configVolumes == nil {
return nil
}
result := map[string]struct{}{}
for key := range configVolumes {
result[key] = struct{}{}
}
return result
}
func GetDiffIDs(diffIDs []string) []godigest.Digest {
result := make([]godigest.Digest, 0, len(diffIDs))
for i := range diffIDs {
result = append(result, godigest.Digest(diffIDs[i]))
}
return result
}