mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
9074f8483b
feat(metaDB): add more image statistics info Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
395 lines
11 KiB
Go
395 lines
11 KiB
Go
package convert
|
|
|
|
import (
|
|
"time"
|
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
|
|
"zotregistry.io/zot/pkg/common"
|
|
proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
|
|
mTypes "zotregistry.io/zot/pkg/meta/types"
|
|
)
|
|
|
|
func GetProtoRepoMeta(repo mTypes.RepoMeta) *proto_go.RepoMeta {
|
|
return &proto_go.RepoMeta{
|
|
Name: repo.Name,
|
|
Tags: GetProtoTags(repo.Tags),
|
|
Statistics: GetProtoStatistics(repo.Statistics),
|
|
Signatures: GetProtoSignatures(repo.Signatures),
|
|
Referrers: GetProtoReferrers(repo.Referrers),
|
|
Size: int32(repo.Size),
|
|
Vendors: repo.Vendors,
|
|
Platforms: GetProtoPlatforms(repo.Platforms),
|
|
LastUpdatedImage: GetProtoLastUpdatedImage(repo.LastUpdatedImage),
|
|
}
|
|
}
|
|
|
|
func GetProtoImageMeta(imageMeta mTypes.ImageMeta) *proto_go.ImageMeta {
|
|
switch imageMeta.MediaType {
|
|
case ispec.MediaTypeImageManifest:
|
|
if len(imageMeta.Manifests) == 0 {
|
|
return nil
|
|
}
|
|
manifestData := imageMeta.Manifests[0]
|
|
|
|
return GetProtoImageManifestData(manifestData.Manifest, manifestData.Config, manifestData.Size,
|
|
manifestData.Digest.String())
|
|
case ispec.MediaTypeImageIndex:
|
|
if imageMeta.Index == nil {
|
|
return nil
|
|
}
|
|
|
|
return GetProtoImageIndexMeta(*imageMeta.Index, imageMeta.Size, imageMeta.Digest.String())
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func GetProtoImageManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
|
|
) *proto_go.ImageMeta {
|
|
return &proto_go.ImageMeta{
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
Manifests: []*proto_go.ManifestMeta{GetProtoManifestMeta(manifestContent, configContent, size, digest)},
|
|
Index: nil,
|
|
}
|
|
}
|
|
|
|
func GetProtoManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
|
|
) *proto_go.ManifestMeta {
|
|
return &proto_go.ManifestMeta{
|
|
Digest: digest,
|
|
Size: size,
|
|
Manifest: &proto_go.Manifest{
|
|
Versioned: &proto_go.Versioned{SchemaVersion: int32(manifestContent.SchemaVersion)},
|
|
Config: &proto_go.Descriptor{
|
|
Digest: manifestContent.Config.Digest.String(),
|
|
Size: manifestContent.Config.Size,
|
|
MediaType: manifestContent.Config.MediaType,
|
|
},
|
|
MediaType: ref(ispec.MediaTypeImageManifest),
|
|
ArtifactType: &manifestContent.ArtifactType,
|
|
Layers: getProtoManifestLayers(manifestContent.Layers),
|
|
Subject: getProtoDesc(manifestContent.Subject),
|
|
Annotations: manifestContent.Annotations,
|
|
},
|
|
Config: &proto_go.Image{
|
|
Created: GetProtoTime(configContent.Created),
|
|
Author: &configContent.Author,
|
|
Platform: GetProtoPlatform(&configContent.Platform),
|
|
Config: &proto_go.ImageConfig{
|
|
User: configContent.Config.User,
|
|
ExposedPorts: getProtoExposedPorts(configContent.Config.ExposedPorts),
|
|
Env: configContent.Config.Env,
|
|
Entrypoint: configContent.Config.Entrypoint,
|
|
Cmd: configContent.Config.Cmd,
|
|
Volumes: getProtoConfigVolumes(configContent.Config.Volumes),
|
|
WorkingDir: &configContent.Config.WorkingDir,
|
|
Labels: configContent.Config.Labels,
|
|
StopSignal: &configContent.Config.StopSignal,
|
|
},
|
|
RootFS: &proto_go.RootFS{
|
|
Type: configContent.RootFS.Type,
|
|
DiffIDs: getProtoDiffIDs(configContent.RootFS.DiffIDs),
|
|
},
|
|
History: getProtoHistory(configContent.History),
|
|
},
|
|
}
|
|
}
|
|
|
|
func GetProtoImageIndexMeta(indexContent ispec.Index, size int64, digest string) *proto_go.ImageMeta {
|
|
return &proto_go.ImageMeta{
|
|
MediaType: ispec.MediaTypeImageIndex,
|
|
Index: &proto_go.IndexMeta{
|
|
Size: size,
|
|
Digest: digest,
|
|
Index: &proto_go.Index{
|
|
Versioned: &proto_go.Versioned{SchemaVersion: int32(indexContent.Versioned.SchemaVersion)},
|
|
MediaType: ref(ispec.MediaTypeImageIndex),
|
|
ArtifactType: ref(common.GetIndexArtifactType(indexContent)),
|
|
Manifests: getProtoManifestList(indexContent.Manifests),
|
|
Subject: getProtoDesc(indexContent.Subject),
|
|
Annotations: indexContent.Annotations,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func GetProtoStatistics(stats map[string]mTypes.DescriptorStatistics) map[string]*proto_go.DescriptorStatistics {
|
|
results := map[string]*proto_go.DescriptorStatistics{}
|
|
|
|
for digest, stat := range stats {
|
|
results[digest] = &proto_go.DescriptorStatistics{
|
|
DownloadCount: int32(stat.DownloadCount),
|
|
LastPullTimestamp: timestamppb.New(stat.LastPullTimestamp),
|
|
PushTimestamp: timestamppb.New(stat.PushTimestamp),
|
|
PushedBy: stat.PushedBy,
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
func GetProtoPlatforms(platforms []ispec.Platform) []*proto_go.Platform {
|
|
result := []*proto_go.Platform{}
|
|
|
|
for i := range platforms {
|
|
result = append(result, &proto_go.Platform{
|
|
OS: platforms[i].OS,
|
|
Architecture: platforms[i].Architecture,
|
|
})
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func GetProtoReferrers(refs map[string][]mTypes.ReferrerInfo) map[string]*proto_go.ReferrersInfo {
|
|
results := map[string]*proto_go.ReferrersInfo{}
|
|
|
|
for digest, ref := range refs {
|
|
referrersInfoList := []*proto_go.ReferrerInfo{}
|
|
|
|
for _, dbRef := range ref {
|
|
referrersInfoList = append(referrersInfoList, GetProtoReferrerInfo(dbRef))
|
|
}
|
|
|
|
results[digest] = &proto_go.ReferrersInfo{List: referrersInfoList}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
func GetProtoSignatures(sigs map[string]mTypes.ManifestSignatures) map[string]*proto_go.ManifestSignatures {
|
|
results := map[string]*proto_go.ManifestSignatures{}
|
|
|
|
for digest, dbSignatures := range sigs {
|
|
imageSignatures := &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{}}
|
|
|
|
for signatureName, signatureInfo := range dbSignatures {
|
|
imageSignatures.Map[signatureName] = &proto_go.SignaturesInfo{List: GetProtoSignaturesInfo(signatureInfo)}
|
|
}
|
|
|
|
results[digest] = imageSignatures
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
func GetProtoSignaturesInfo(sigsInfo []mTypes.SignatureInfo) []*proto_go.SignatureInfo {
|
|
results := []*proto_go.SignatureInfo{}
|
|
|
|
for _, sigInfo := range sigsInfo {
|
|
results = append(results, &proto_go.SignatureInfo{
|
|
SignatureManifestDigest: sigInfo.SignatureManifestDigest,
|
|
LayersInfo: GetProtoLayersInfo(sigInfo.LayersInfo),
|
|
})
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
func GetProtoLayersInfo(layersInfo []mTypes.LayerInfo) []*proto_go.LayersInfo {
|
|
result := make([]*proto_go.LayersInfo, 0, len(layersInfo))
|
|
|
|
for _, layerInfo := range layersInfo {
|
|
result = append(result, &proto_go.LayersInfo{
|
|
LayerDigest: layerInfo.LayerDigest,
|
|
LayerContent: layerInfo.LayerContent,
|
|
SignatureKey: layerInfo.SignatureKey,
|
|
Signer: layerInfo.Signer,
|
|
Date: timestamppb.New(layerInfo.Date),
|
|
})
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func getProtoManifestLayers(layers []ispec.Descriptor) []*proto_go.Descriptor {
|
|
protoLayers := []*proto_go.Descriptor{}
|
|
|
|
for _, layer := range layers {
|
|
layer := layer
|
|
|
|
protoLayers = append(protoLayers, getProtoDesc(&layer))
|
|
}
|
|
|
|
return protoLayers
|
|
}
|
|
|
|
func getProtoDesc(descriptor *ispec.Descriptor) *proto_go.Descriptor {
|
|
if descriptor == nil {
|
|
return nil
|
|
}
|
|
|
|
return &proto_go.Descriptor{
|
|
MediaType: descriptor.MediaType,
|
|
Digest: descriptor.Digest.String(),
|
|
Size: descriptor.Size,
|
|
URLs: descriptor.URLs,
|
|
Annotations: descriptor.Annotations,
|
|
Data: descriptor.Data,
|
|
Platform: GetProtoPlatform(descriptor.Platform),
|
|
ArtifactType: &descriptor.ArtifactType,
|
|
}
|
|
}
|
|
|
|
func getProtoManifestList(manifests []ispec.Descriptor) []*proto_go.Descriptor {
|
|
result := make([]*proto_go.Descriptor, 0, len(manifests))
|
|
|
|
for _, manifest := range manifests {
|
|
result = append(result, &proto_go.Descriptor{
|
|
MediaType: manifest.MediaType,
|
|
Digest: manifest.Digest.String(),
|
|
Size: manifest.Size,
|
|
URLs: manifest.URLs,
|
|
Annotations: manifest.Annotations,
|
|
Data: manifest.Data,
|
|
Platform: GetProtoPlatform(manifest.Platform),
|
|
ArtifactType: ref(manifest.ArtifactType),
|
|
})
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func GetProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
|
|
if platform == nil {
|
|
return nil
|
|
}
|
|
|
|
return &proto_go.Platform{
|
|
Architecture: platform.Architecture,
|
|
OS: platform.OS,
|
|
OSVersion: ref(platform.OSVersion),
|
|
OSFeatures: platform.OSFeatures,
|
|
Variant: ref(platform.Variant),
|
|
}
|
|
}
|
|
|
|
func getProtoHistory(historySlice []ispec.History) []*proto_go.History {
|
|
protoHistory := []*proto_go.History{}
|
|
|
|
for _, history := range historySlice {
|
|
history := history
|
|
|
|
protoHistory = append(protoHistory, &proto_go.History{
|
|
Created: GetProtoTime(history.Created),
|
|
CreatedBy: &history.CreatedBy,
|
|
Author: &history.Author,
|
|
Comment: &history.Comment,
|
|
EmptyLayer: &history.EmptyLayer,
|
|
})
|
|
}
|
|
|
|
return protoHistory
|
|
}
|
|
|
|
func getProtoDiffIDs(digests []godigest.Digest) []string {
|
|
digestsStr := []string{}
|
|
|
|
for _, digest := range digests {
|
|
digestsStr = append(digestsStr, digest.String())
|
|
}
|
|
|
|
return digestsStr
|
|
}
|
|
|
|
func getProtoExposedPorts(exposedPorts map[string]struct{}) map[string]*proto_go.EmptyMessage {
|
|
protoPorts := map[string]*proto_go.EmptyMessage{}
|
|
|
|
for i := range exposedPorts {
|
|
protoPorts[i] = &proto_go.EmptyMessage{}
|
|
}
|
|
|
|
return protoPorts
|
|
}
|
|
|
|
func getProtoConfigVolumes(volumes map[string]struct{}) map[string]*proto_go.EmptyMessage {
|
|
protoVolumes := map[string]*proto_go.EmptyMessage{}
|
|
|
|
for i := range volumes {
|
|
protoVolumes[i] = &proto_go.EmptyMessage{}
|
|
}
|
|
|
|
return protoVolumes
|
|
}
|
|
|
|
func GetProtoReferrerInfo(referrer mTypes.ReferrerInfo) *proto_go.ReferrerInfo {
|
|
return &proto_go.ReferrerInfo{
|
|
Digest: referrer.Digest,
|
|
MediaType: referrer.MediaType,
|
|
ArtifactType: referrer.ArtifactType,
|
|
Size: int64(referrer.Size),
|
|
Annotations: referrer.Annotations,
|
|
}
|
|
}
|
|
|
|
func GetProtoTime(time *time.Time) *timestamppb.Timestamp {
|
|
if time == nil {
|
|
return nil
|
|
}
|
|
|
|
return timestamppb.New(*time)
|
|
}
|
|
|
|
func GetProtoTags(tags map[string]mTypes.Descriptor) map[string]*proto_go.TagDescriptor {
|
|
resultMap := map[string]*proto_go.TagDescriptor{}
|
|
|
|
for tag, tagDescriptor := range tags {
|
|
resultMap[tag] = &proto_go.TagDescriptor{
|
|
Digest: tagDescriptor.Digest,
|
|
MediaType: tagDescriptor.MediaType,
|
|
}
|
|
}
|
|
|
|
return resultMap
|
|
}
|
|
|
|
func GetProtoLastUpdatedImage(lastUpdatedImage *mTypes.LastUpdatedImage) *proto_go.RepoLastUpdatedImage {
|
|
if lastUpdatedImage == nil {
|
|
return nil
|
|
}
|
|
|
|
return &proto_go.RepoLastUpdatedImage{
|
|
LastUpdated: GetProtoTime(lastUpdatedImage.LastUpdated),
|
|
MediaType: lastUpdatedImage.MediaType,
|
|
Digest: lastUpdatedImage.Digest,
|
|
Tag: lastUpdatedImage.Tag,
|
|
}
|
|
}
|
|
|
|
func GetProtoEarlierUpdatedImage(repoLastImage *proto_go.RepoLastUpdatedImage, lastImage *proto_go.RepoLastUpdatedImage,
|
|
) *proto_go.RepoLastUpdatedImage {
|
|
if repoLastImage == nil {
|
|
return lastImage
|
|
}
|
|
|
|
if lastImage == nil || lastImage.LastUpdated == nil {
|
|
return repoLastImage
|
|
}
|
|
|
|
if repoLastImage.LastUpdated == nil {
|
|
return lastImage
|
|
}
|
|
|
|
if repoLastImage.LastUpdated.AsTime().Before(lastImage.LastUpdated.AsTime()) {
|
|
return lastImage
|
|
}
|
|
|
|
return repoLastImage
|
|
}
|
|
|
|
func ref[T any](input T) *T {
|
|
ref := input
|
|
|
|
return &ref
|
|
}
|
|
|
|
func deref[T any](pointer *T, defaultVal T) T {
|
|
if pointer != nil {
|
|
return *pointer
|
|
}
|
|
|
|
return defaultVal
|
|
}
|