zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/meta/convert/convert_proto.go (about)

     1  package convert
     2  
     3  import (
     4  	"time"
     5  
     6  	godigest "github.com/opencontainers/go-digest"
     7  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
     8  	"google.golang.org/protobuf/types/known/timestamppb"
     9  
    10  	"zotregistry.dev/zot/pkg/common"
    11  	proto_go "zotregistry.dev/zot/pkg/meta/proto/gen"
    12  	mTypes "zotregistry.dev/zot/pkg/meta/types"
    13  )
    14  
    15  func GetProtoRepoMeta(repo mTypes.RepoMeta) *proto_go.RepoMeta {
    16  	return &proto_go.RepoMeta{
    17  		Name:             repo.Name,
    18  		Tags:             GetProtoTags(repo.Tags),
    19  		Statistics:       GetProtoStatistics(repo.Statistics),
    20  		Signatures:       GetProtoSignatures(repo.Signatures),
    21  		Referrers:        GetProtoReferrers(repo.Referrers),
    22  		Size:             repo.Size,
    23  		Vendors:          repo.Vendors,
    24  		Platforms:        GetProtoPlatforms(repo.Platforms),
    25  		LastUpdatedImage: GetProtoLastUpdatedImage(repo.LastUpdatedImage),
    26  		Stars:            int32(repo.StarCount),
    27  		Downloads:        int32(repo.DownloadCount),
    28  	}
    29  }
    30  
    31  func GetProtoImageMeta(imageMeta mTypes.ImageMeta) *proto_go.ImageMeta {
    32  	switch imageMeta.MediaType {
    33  	case ispec.MediaTypeImageManifest:
    34  		if len(imageMeta.Manifests) == 0 {
    35  			return nil
    36  		}
    37  		manifestData := imageMeta.Manifests[0]
    38  
    39  		return GetProtoImageManifestData(manifestData.Manifest, manifestData.Config, manifestData.Size,
    40  			manifestData.Digest.String())
    41  	case ispec.MediaTypeImageIndex:
    42  		if imageMeta.Index == nil {
    43  			return nil
    44  		}
    45  
    46  		return GetProtoImageIndexMeta(*imageMeta.Index, imageMeta.Size, imageMeta.Digest.String())
    47  	default:
    48  		return nil
    49  	}
    50  }
    51  
    52  func GetProtoImageManifestData(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
    53  ) *proto_go.ImageMeta {
    54  	return &proto_go.ImageMeta{
    55  		MediaType: ispec.MediaTypeImageManifest,
    56  		Manifests: []*proto_go.ManifestMeta{GetProtoManifestMeta(manifestContent, configContent, size, digest)},
    57  		Index:     nil,
    58  	}
    59  }
    60  
    61  func GetProtoManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64, digest string,
    62  ) *proto_go.ManifestMeta {
    63  	return &proto_go.ManifestMeta{
    64  		Digest: digest,
    65  		Size:   size,
    66  		Manifest: &proto_go.Manifest{
    67  			Versioned: &proto_go.Versioned{SchemaVersion: int32(manifestContent.SchemaVersion)},
    68  			Config: &proto_go.Descriptor{
    69  				Digest:    manifestContent.Config.Digest.String(),
    70  				Size:      manifestContent.Config.Size,
    71  				MediaType: manifestContent.Config.MediaType,
    72  			},
    73  			MediaType:    ref(ispec.MediaTypeImageManifest),
    74  			ArtifactType: &manifestContent.ArtifactType,
    75  			Layers:       getProtoManifestLayers(manifestContent.Layers),
    76  			Subject:      getProtoDesc(manifestContent.Subject),
    77  			Annotations:  manifestContent.Annotations,
    78  		},
    79  		Config: &proto_go.Image{
    80  			Created:  GetProtoTime(configContent.Created),
    81  			Author:   &configContent.Author,
    82  			Platform: GetProtoPlatform(&configContent.Platform),
    83  			Config: &proto_go.ImageConfig{
    84  				User:         configContent.Config.User,
    85  				ExposedPorts: getProtoExposedPorts(configContent.Config.ExposedPorts),
    86  				Env:          configContent.Config.Env,
    87  				Entrypoint:   configContent.Config.Entrypoint,
    88  				Cmd:          configContent.Config.Cmd,
    89  				Volumes:      getProtoConfigVolumes(configContent.Config.Volumes),
    90  				WorkingDir:   &configContent.Config.WorkingDir,
    91  				Labels:       configContent.Config.Labels,
    92  				StopSignal:   &configContent.Config.StopSignal,
    93  			},
    94  			RootFS: &proto_go.RootFS{
    95  				Type:    configContent.RootFS.Type,
    96  				DiffIDs: getProtoDiffIDs(configContent.RootFS.DiffIDs),
    97  			},
    98  			History: getProtoHistory(configContent.History),
    99  		},
   100  	}
   101  }
   102  
   103  func GetProtoImageIndexMeta(indexContent ispec.Index, size int64, digest string) *proto_go.ImageMeta {
   104  	return &proto_go.ImageMeta{
   105  		MediaType: ispec.MediaTypeImageIndex,
   106  		Index: &proto_go.IndexMeta{
   107  			Size:   size,
   108  			Digest: digest,
   109  			Index: &proto_go.Index{
   110  				Versioned:    &proto_go.Versioned{SchemaVersion: int32(indexContent.Versioned.SchemaVersion)},
   111  				MediaType:    ref(ispec.MediaTypeImageIndex),
   112  				ArtifactType: ref(common.GetIndexArtifactType(indexContent)),
   113  				Manifests:    getProtoManifestList(indexContent.Manifests),
   114  				Subject:      getProtoDesc(indexContent.Subject),
   115  				Annotations:  indexContent.Annotations,
   116  			},
   117  		},
   118  	}
   119  }
   120  
   121  func GetProtoStatistics(stats map[mTypes.ImageDigest]mTypes.DescriptorStatistics,
   122  ) map[mTypes.ImageDigest]*proto_go.DescriptorStatistics {
   123  	results := map[mTypes.ImageDigest]*proto_go.DescriptorStatistics{}
   124  
   125  	for digest, stat := range stats {
   126  		results[digest] = &proto_go.DescriptorStatistics{
   127  			DownloadCount:     int32(stat.DownloadCount),
   128  			LastPullTimestamp: timestamppb.New(stat.LastPullTimestamp),
   129  			PushTimestamp:     timestamppb.New(stat.PushTimestamp),
   130  			PushedBy:          stat.PushedBy,
   131  		}
   132  	}
   133  
   134  	return results
   135  }
   136  
   137  func GetProtoPlatforms(platforms []ispec.Platform) []*proto_go.Platform {
   138  	result := []*proto_go.Platform{}
   139  
   140  	for i := range platforms {
   141  		result = append(result, &proto_go.Platform{
   142  			OS:           platforms[i].OS,
   143  			Architecture: platforms[i].Architecture,
   144  		})
   145  	}
   146  
   147  	return result
   148  }
   149  
   150  func GetProtoReferrers(refs map[string][]mTypes.ReferrerInfo) map[string]*proto_go.ReferrersInfo {
   151  	results := map[string]*proto_go.ReferrersInfo{}
   152  
   153  	for digest, ref := range refs {
   154  		referrersInfoList := []*proto_go.ReferrerInfo{}
   155  
   156  		for _, dbRef := range ref {
   157  			referrersInfoList = append(referrersInfoList, GetProtoReferrerInfo(dbRef))
   158  		}
   159  
   160  		results[digest] = &proto_go.ReferrersInfo{List: referrersInfoList}
   161  	}
   162  
   163  	return results
   164  }
   165  
   166  func GetProtoSignatures(sigs map[string]mTypes.ManifestSignatures) map[string]*proto_go.ManifestSignatures {
   167  	results := map[string]*proto_go.ManifestSignatures{}
   168  
   169  	for digest, dbSignatures := range sigs {
   170  		imageSignatures := &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{}}
   171  
   172  		for signatureName, signatureInfo := range dbSignatures {
   173  			imageSignatures.Map[signatureName] = &proto_go.SignaturesInfo{List: GetProtoSignaturesInfo(signatureInfo)}
   174  		}
   175  
   176  		results[digest] = imageSignatures
   177  	}
   178  
   179  	return results
   180  }
   181  
   182  func GetProtoSignaturesInfo(sigsInfo []mTypes.SignatureInfo) []*proto_go.SignatureInfo {
   183  	results := []*proto_go.SignatureInfo{}
   184  
   185  	for _, sigInfo := range sigsInfo {
   186  		results = append(results, &proto_go.SignatureInfo{
   187  			SignatureManifestDigest: sigInfo.SignatureManifestDigest,
   188  			LayersInfo:              GetProtoLayersInfo(sigInfo.LayersInfo),
   189  		})
   190  	}
   191  
   192  	return results
   193  }
   194  
   195  func GetProtoLayersInfo(layersInfo []mTypes.LayerInfo) []*proto_go.LayersInfo {
   196  	result := make([]*proto_go.LayersInfo, 0, len(layersInfo))
   197  
   198  	for _, layerInfo := range layersInfo {
   199  		result = append(result, &proto_go.LayersInfo{
   200  			LayerDigest:  layerInfo.LayerDigest,
   201  			LayerContent: layerInfo.LayerContent,
   202  			SignatureKey: layerInfo.SignatureKey,
   203  			Signer:       layerInfo.Signer,
   204  			Date:         timestamppb.New(layerInfo.Date),
   205  		})
   206  	}
   207  
   208  	return result
   209  }
   210  
   211  func getProtoManifestLayers(layers []ispec.Descriptor) []*proto_go.Descriptor {
   212  	protoLayers := []*proto_go.Descriptor{}
   213  
   214  	for _, layer := range layers {
   215  		layer := layer
   216  
   217  		protoLayers = append(protoLayers, getProtoDesc(&layer))
   218  	}
   219  
   220  	return protoLayers
   221  }
   222  
   223  func getProtoDesc(descriptor *ispec.Descriptor) *proto_go.Descriptor {
   224  	if descriptor == nil {
   225  		return nil
   226  	}
   227  
   228  	return &proto_go.Descriptor{
   229  		MediaType:    descriptor.MediaType,
   230  		Digest:       descriptor.Digest.String(),
   231  		Size:         descriptor.Size,
   232  		URLs:         descriptor.URLs,
   233  		Annotations:  descriptor.Annotations,
   234  		Data:         descriptor.Data,
   235  		Platform:     GetProtoPlatform(descriptor.Platform),
   236  		ArtifactType: &descriptor.ArtifactType,
   237  	}
   238  }
   239  
   240  func getProtoManifestList(manifests []ispec.Descriptor) []*proto_go.Descriptor {
   241  	result := make([]*proto_go.Descriptor, 0, len(manifests))
   242  
   243  	for _, manifest := range manifests {
   244  		result = append(result, &proto_go.Descriptor{
   245  			MediaType:    manifest.MediaType,
   246  			Digest:       manifest.Digest.String(),
   247  			Size:         manifest.Size,
   248  			URLs:         manifest.URLs,
   249  			Annotations:  manifest.Annotations,
   250  			Data:         manifest.Data,
   251  			Platform:     GetProtoPlatform(manifest.Platform),
   252  			ArtifactType: ref(manifest.ArtifactType),
   253  		})
   254  	}
   255  
   256  	return result
   257  }
   258  
   259  func GetProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
   260  	if platform == nil {
   261  		return nil
   262  	}
   263  
   264  	return &proto_go.Platform{
   265  		Architecture: platform.Architecture,
   266  		OS:           platform.OS,
   267  		OSVersion:    ref(platform.OSVersion),
   268  		OSFeatures:   platform.OSFeatures,
   269  		Variant:      ref(platform.Variant),
   270  	}
   271  }
   272  
   273  func getProtoHistory(historySlice []ispec.History) []*proto_go.History {
   274  	protoHistory := []*proto_go.History{}
   275  
   276  	for _, history := range historySlice {
   277  		history := history
   278  
   279  		protoHistory = append(protoHistory, &proto_go.History{
   280  			Created:    GetProtoTime(history.Created),
   281  			CreatedBy:  &history.CreatedBy,
   282  			Author:     &history.Author,
   283  			Comment:    &history.Comment,
   284  			EmptyLayer: &history.EmptyLayer,
   285  		})
   286  	}
   287  
   288  	return protoHistory
   289  }
   290  
   291  func getProtoDiffIDs(digests []godigest.Digest) []string {
   292  	digestsStr := []string{}
   293  
   294  	for _, digest := range digests {
   295  		digestsStr = append(digestsStr, digest.String())
   296  	}
   297  
   298  	return digestsStr
   299  }
   300  
   301  func getProtoExposedPorts(exposedPorts map[string]struct{}) map[string]*proto_go.EmptyMessage {
   302  	protoPorts := map[string]*proto_go.EmptyMessage{}
   303  
   304  	for i := range exposedPorts {
   305  		protoPorts[i] = &proto_go.EmptyMessage{}
   306  	}
   307  
   308  	return protoPorts
   309  }
   310  
   311  func getProtoConfigVolumes(volumes map[string]struct{}) map[string]*proto_go.EmptyMessage {
   312  	protoVolumes := map[string]*proto_go.EmptyMessage{}
   313  
   314  	for i := range volumes {
   315  		protoVolumes[i] = &proto_go.EmptyMessage{}
   316  	}
   317  
   318  	return protoVolumes
   319  }
   320  
   321  func GetProtoReferrerInfo(referrer mTypes.ReferrerInfo) *proto_go.ReferrerInfo {
   322  	return &proto_go.ReferrerInfo{
   323  		Digest:       referrer.Digest,
   324  		MediaType:    referrer.MediaType,
   325  		ArtifactType: referrer.ArtifactType,
   326  		Size:         int64(referrer.Size),
   327  		Annotations:  referrer.Annotations,
   328  	}
   329  }
   330  
   331  func GetProtoTime(time *time.Time) *timestamppb.Timestamp {
   332  	if time == nil {
   333  		return nil
   334  	}
   335  
   336  	return timestamppb.New(*time)
   337  }
   338  
   339  func GetProtoTags(tags map[mTypes.Tag]mTypes.Descriptor) map[mTypes.Tag]*proto_go.TagDescriptor {
   340  	resultMap := map[mTypes.Tag]*proto_go.TagDescriptor{}
   341  
   342  	for tag, tagDescriptor := range tags {
   343  		resultMap[tag] = &proto_go.TagDescriptor{
   344  			Digest:    tagDescriptor.Digest,
   345  			MediaType: tagDescriptor.MediaType,
   346  		}
   347  	}
   348  
   349  	return resultMap
   350  }
   351  
   352  func GetProtoLastUpdatedImage(lastUpdatedImage *mTypes.LastUpdatedImage) *proto_go.RepoLastUpdatedImage {
   353  	if lastUpdatedImage == nil {
   354  		return nil
   355  	}
   356  
   357  	return &proto_go.RepoLastUpdatedImage{
   358  		LastUpdated: GetProtoTime(lastUpdatedImage.LastUpdated),
   359  		MediaType:   lastUpdatedImage.MediaType,
   360  		Digest:      lastUpdatedImage.Digest,
   361  		Tag:         lastUpdatedImage.Tag,
   362  	}
   363  }
   364  
   365  func GetProtoEarlierUpdatedImage(repoLastImage *proto_go.RepoLastUpdatedImage, lastImage *proto_go.RepoLastUpdatedImage,
   366  ) *proto_go.RepoLastUpdatedImage {
   367  	if repoLastImage == nil {
   368  		return lastImage
   369  	}
   370  
   371  	if lastImage == nil || lastImage.LastUpdated == nil {
   372  		return repoLastImage
   373  	}
   374  
   375  	if repoLastImage.LastUpdated == nil {
   376  		return lastImage
   377  	}
   378  
   379  	if repoLastImage.LastUpdated.AsTime().Before(lastImage.LastUpdated.AsTime()) {
   380  		return lastImage
   381  	}
   382  
   383  	return repoLastImage
   384  }
   385  
   386  func ref[T any](input T) *T {
   387  	ref := input
   388  
   389  	return &ref
   390  }
   391  
   392  func deref[T any](pointer *T, defaultVal T) T {
   393  	if pointer != nil {
   394  		return *pointer
   395  	}
   396  
   397  	return defaultVal
   398  }