zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/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.io/zot/pkg/common"
    11  	proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
    12  	mTypes "zotregistry.io/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:             int32(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[string]mTypes.DescriptorStatistics) map[string]*proto_go.DescriptorStatistics {
   122  	results := map[string]*proto_go.DescriptorStatistics{}
   123  
   124  	for digest, stat := range stats {
   125  		results[digest] = &proto_go.DescriptorStatistics{
   126  			DownloadCount:     int32(stat.DownloadCount),
   127  			LastPullTimestamp: timestamppb.New(stat.LastPullTimestamp),
   128  			PushTimestamp:     timestamppb.New(stat.PushTimestamp),
   129  			PushedBy:          stat.PushedBy,
   130  		}
   131  	}
   132  
   133  	return results
   134  }
   135  
   136  func GetProtoPlatforms(platforms []ispec.Platform) []*proto_go.Platform {
   137  	result := []*proto_go.Platform{}
   138  
   139  	for i := range platforms {
   140  		result = append(result, &proto_go.Platform{
   141  			OS:           platforms[i].OS,
   142  			Architecture: platforms[i].Architecture,
   143  		})
   144  	}
   145  
   146  	return result
   147  }
   148  
   149  func GetProtoReferrers(refs map[string][]mTypes.ReferrerInfo) map[string]*proto_go.ReferrersInfo {
   150  	results := map[string]*proto_go.ReferrersInfo{}
   151  
   152  	for digest, ref := range refs {
   153  		referrersInfoList := []*proto_go.ReferrerInfo{}
   154  
   155  		for _, dbRef := range ref {
   156  			referrersInfoList = append(referrersInfoList, GetProtoReferrerInfo(dbRef))
   157  		}
   158  
   159  		results[digest] = &proto_go.ReferrersInfo{List: referrersInfoList}
   160  	}
   161  
   162  	return results
   163  }
   164  
   165  func GetProtoSignatures(sigs map[string]mTypes.ManifestSignatures) map[string]*proto_go.ManifestSignatures {
   166  	results := map[string]*proto_go.ManifestSignatures{}
   167  
   168  	for digest, dbSignatures := range sigs {
   169  		imageSignatures := &proto_go.ManifestSignatures{Map: map[string]*proto_go.SignaturesInfo{}}
   170  
   171  		for signatureName, signatureInfo := range dbSignatures {
   172  			imageSignatures.Map[signatureName] = &proto_go.SignaturesInfo{List: GetProtoSignaturesInfo(signatureInfo)}
   173  		}
   174  
   175  		results[digest] = imageSignatures
   176  	}
   177  
   178  	return results
   179  }
   180  
   181  func GetProtoSignaturesInfo(sigsInfo []mTypes.SignatureInfo) []*proto_go.SignatureInfo {
   182  	results := []*proto_go.SignatureInfo{}
   183  
   184  	for _, sigInfo := range sigsInfo {
   185  		results = append(results, &proto_go.SignatureInfo{
   186  			SignatureManifestDigest: sigInfo.SignatureManifestDigest,
   187  			LayersInfo:              GetProtoLayersInfo(sigInfo.LayersInfo),
   188  		})
   189  	}
   190  
   191  	return results
   192  }
   193  
   194  func GetProtoLayersInfo(layersInfo []mTypes.LayerInfo) []*proto_go.LayersInfo {
   195  	result := make([]*proto_go.LayersInfo, 0, len(layersInfo))
   196  
   197  	for _, layerInfo := range layersInfo {
   198  		result = append(result, &proto_go.LayersInfo{
   199  			LayerDigest:  layerInfo.LayerDigest,
   200  			LayerContent: layerInfo.LayerContent,
   201  			SignatureKey: layerInfo.SignatureKey,
   202  			Signer:       layerInfo.Signer,
   203  			Date:         timestamppb.New(layerInfo.Date),
   204  		})
   205  	}
   206  
   207  	return result
   208  }
   209  
   210  func getProtoManifestLayers(layers []ispec.Descriptor) []*proto_go.Descriptor {
   211  	protoLayers := []*proto_go.Descriptor{}
   212  
   213  	for _, layer := range layers {
   214  		layer := layer
   215  
   216  		protoLayers = append(protoLayers, getProtoDesc(&layer))
   217  	}
   218  
   219  	return protoLayers
   220  }
   221  
   222  func getProtoDesc(descriptor *ispec.Descriptor) *proto_go.Descriptor {
   223  	if descriptor == nil {
   224  		return nil
   225  	}
   226  
   227  	return &proto_go.Descriptor{
   228  		MediaType:    descriptor.MediaType,
   229  		Digest:       descriptor.Digest.String(),
   230  		Size:         descriptor.Size,
   231  		URLs:         descriptor.URLs,
   232  		Annotations:  descriptor.Annotations,
   233  		Data:         descriptor.Data,
   234  		Platform:     GetProtoPlatform(descriptor.Platform),
   235  		ArtifactType: &descriptor.ArtifactType,
   236  	}
   237  }
   238  
   239  func getProtoManifestList(manifests []ispec.Descriptor) []*proto_go.Descriptor {
   240  	result := make([]*proto_go.Descriptor, 0, len(manifests))
   241  
   242  	for _, manifest := range manifests {
   243  		result = append(result, &proto_go.Descriptor{
   244  			MediaType:    manifest.MediaType,
   245  			Digest:       manifest.Digest.String(),
   246  			Size:         manifest.Size,
   247  			URLs:         manifest.URLs,
   248  			Annotations:  manifest.Annotations,
   249  			Data:         manifest.Data,
   250  			Platform:     GetProtoPlatform(manifest.Platform),
   251  			ArtifactType: ref(manifest.ArtifactType),
   252  		})
   253  	}
   254  
   255  	return result
   256  }
   257  
   258  func GetProtoPlatform(platform *ispec.Platform) *proto_go.Platform {
   259  	if platform == nil {
   260  		return nil
   261  	}
   262  
   263  	return &proto_go.Platform{
   264  		Architecture: platform.Architecture,
   265  		OS:           platform.OS,
   266  		OSVersion:    ref(platform.OSVersion),
   267  		OSFeatures:   platform.OSFeatures,
   268  		Variant:      ref(platform.Variant),
   269  	}
   270  }
   271  
   272  func getProtoHistory(historySlice []ispec.History) []*proto_go.History {
   273  	protoHistory := []*proto_go.History{}
   274  
   275  	for _, history := range historySlice {
   276  		history := history
   277  
   278  		protoHistory = append(protoHistory, &proto_go.History{
   279  			Created:    GetProtoTime(history.Created),
   280  			CreatedBy:  &history.CreatedBy,
   281  			Author:     &history.Author,
   282  			Comment:    &history.Comment,
   283  			EmptyLayer: &history.EmptyLayer,
   284  		})
   285  	}
   286  
   287  	return protoHistory
   288  }
   289  
   290  func getProtoDiffIDs(digests []godigest.Digest) []string {
   291  	digestsStr := []string{}
   292  
   293  	for _, digest := range digests {
   294  		digestsStr = append(digestsStr, digest.String())
   295  	}
   296  
   297  	return digestsStr
   298  }
   299  
   300  func getProtoExposedPorts(exposedPorts map[string]struct{}) map[string]*proto_go.EmptyMessage {
   301  	protoPorts := map[string]*proto_go.EmptyMessage{}
   302  
   303  	for i := range exposedPorts {
   304  		protoPorts[i] = &proto_go.EmptyMessage{}
   305  	}
   306  
   307  	return protoPorts
   308  }
   309  
   310  func getProtoConfigVolumes(volumes map[string]struct{}) map[string]*proto_go.EmptyMessage {
   311  	protoVolumes := map[string]*proto_go.EmptyMessage{}
   312  
   313  	for i := range volumes {
   314  		protoVolumes[i] = &proto_go.EmptyMessage{}
   315  	}
   316  
   317  	return protoVolumes
   318  }
   319  
   320  func GetProtoReferrerInfo(referrer mTypes.ReferrerInfo) *proto_go.ReferrerInfo {
   321  	return &proto_go.ReferrerInfo{
   322  		Digest:       referrer.Digest,
   323  		MediaType:    referrer.MediaType,
   324  		ArtifactType: referrer.ArtifactType,
   325  		Size:         int64(referrer.Size),
   326  		Annotations:  referrer.Annotations,
   327  	}
   328  }
   329  
   330  func GetProtoTime(time *time.Time) *timestamppb.Timestamp {
   331  	if time == nil {
   332  		return nil
   333  	}
   334  
   335  	return timestamppb.New(*time)
   336  }
   337  
   338  func GetProtoTags(tags map[string]mTypes.Descriptor) map[string]*proto_go.TagDescriptor {
   339  	resultMap := map[string]*proto_go.TagDescriptor{}
   340  
   341  	for tag, tagDescriptor := range tags {
   342  		resultMap[tag] = &proto_go.TagDescriptor{
   343  			Digest:    tagDescriptor.Digest,
   344  			MediaType: tagDescriptor.MediaType,
   345  		}
   346  	}
   347  
   348  	return resultMap
   349  }
   350  
   351  func GetProtoLastUpdatedImage(lastUpdatedImage *mTypes.LastUpdatedImage) *proto_go.RepoLastUpdatedImage {
   352  	if lastUpdatedImage == nil {
   353  		return nil
   354  	}
   355  
   356  	return &proto_go.RepoLastUpdatedImage{
   357  		LastUpdated: GetProtoTime(lastUpdatedImage.LastUpdated),
   358  		MediaType:   lastUpdatedImage.MediaType,
   359  		Digest:      lastUpdatedImage.Digest,
   360  		Tag:         lastUpdatedImage.Tag,
   361  	}
   362  }
   363  
   364  func GetProtoEarlierUpdatedImage(repoLastImage *proto_go.RepoLastUpdatedImage, lastImage *proto_go.RepoLastUpdatedImage,
   365  ) *proto_go.RepoLastUpdatedImage {
   366  	if repoLastImage == nil {
   367  		return lastImage
   368  	}
   369  
   370  	if lastImage == nil || lastImage.LastUpdated == nil {
   371  		return repoLastImage
   372  	}
   373  
   374  	if repoLastImage.LastUpdated == nil {
   375  		return lastImage
   376  	}
   377  
   378  	if repoLastImage.LastUpdated.AsTime().Before(lastImage.LastUpdated.AsTime()) {
   379  		return lastImage
   380  	}
   381  
   382  	return repoLastImage
   383  }
   384  
   385  func ref[T any](input T) *T {
   386  	ref := input
   387  
   388  	return &ref
   389  }
   390  
   391  func deref[T any](pointer *T, defaultVal T) T {
   392  	if pointer != nil {
   393  		return *pointer
   394  	}
   395  
   396  	return defaultVal
   397  }