zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/meta/convert/convert.go (about)

     1  package convert
     2  
     3  import (
     4  	"time"
     5  
     6  	godigest "github.com/opencontainers/go-digest"
     7  	"github.com/opencontainers/image-spec/specs-go"
     8  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
     9  	"google.golang.org/protobuf/types/known/timestamppb"
    10  
    11  	"zotregistry.io/zot/pkg/common"
    12  	proto_go "zotregistry.io/zot/pkg/meta/proto/gen"
    13  	mTypes "zotregistry.io/zot/pkg/meta/types"
    14  )
    15  
    16  func GetHistory(history []*proto_go.History) []ispec.History {
    17  	if history == nil {
    18  		return nil
    19  	}
    20  
    21  	results := make([]ispec.History, 0, len(history))
    22  
    23  	for _, his := range history {
    24  		results = append(results, ispec.History{
    25  			Created:    ref(his.Created.AsTime()),
    26  			CreatedBy:  deref(his.CreatedBy, ""),
    27  			Author:     deref(his.Author, ""),
    28  			Comment:    deref(his.Comment, ""),
    29  			EmptyLayer: deref(his.EmptyLayer, false),
    30  		})
    31  	}
    32  
    33  	return results
    34  }
    35  
    36  func GetImageArtifactType(imageMeta *proto_go.ImageMeta) string {
    37  	switch imageMeta.MediaType {
    38  	case ispec.MediaTypeImageManifest:
    39  		manifestArtifactType := deref(imageMeta.Manifests[0].Manifest.ArtifactType, "")
    40  		if manifestArtifactType != "" {
    41  			return manifestArtifactType
    42  		}
    43  
    44  		return imageMeta.Manifests[0].Manifest.Config.MediaType
    45  	case ispec.MediaTypeImageIndex:
    46  		return deref(imageMeta.Index.Index.ArtifactType, "")
    47  	default:
    48  		return ""
    49  	}
    50  }
    51  
    52  func GetImageManifestSize(imageMeta *proto_go.ImageMeta) int64 {
    53  	switch imageMeta.MediaType {
    54  	case ispec.MediaTypeImageManifest:
    55  		return imageMeta.Manifests[0].Size
    56  	case ispec.MediaTypeImageIndex:
    57  		return imageMeta.Index.Size
    58  	default:
    59  		return 0
    60  	}
    61  }
    62  
    63  func GetImageDigest(imageMeta *proto_go.ImageMeta) godigest.Digest {
    64  	switch imageMeta.MediaType {
    65  	case ispec.MediaTypeImageManifest:
    66  		return godigest.Digest(imageMeta.Manifests[0].Digest)
    67  	case ispec.MediaTypeImageIndex:
    68  		return godigest.Digest(imageMeta.Index.Digest)
    69  	default:
    70  		return ""
    71  	}
    72  }
    73  
    74  func GetImageDigestStr(imageMeta *proto_go.ImageMeta) string {
    75  	switch imageMeta.MediaType {
    76  	case ispec.MediaTypeImageManifest:
    77  		return imageMeta.Manifests[0].Digest
    78  	case ispec.MediaTypeImageIndex:
    79  		return imageMeta.Index.Digest
    80  	default:
    81  		return ""
    82  	}
    83  }
    84  
    85  func GetImageAnnotations(imageMeta *proto_go.ImageMeta) map[string]string {
    86  	switch imageMeta.MediaType {
    87  	case ispec.MediaTypeImageManifest:
    88  		return imageMeta.Manifests[0].Manifest.Annotations
    89  	case ispec.MediaTypeImageIndex:
    90  		return imageMeta.Index.Index.Annotations
    91  	default:
    92  		return map[string]string{}
    93  	}
    94  }
    95  
    96  func GetImageSubject(imageMeta *proto_go.ImageMeta) *ispec.Descriptor {
    97  	switch imageMeta.MediaType {
    98  	case ispec.MediaTypeImageManifest:
    99  		if imageMeta.Manifests[0].Manifest.Subject == nil {
   100  			return nil
   101  		}
   102  
   103  		return GetDescriptorRef(imageMeta.Manifests[0].Manifest.Subject)
   104  	case ispec.MediaTypeImageIndex:
   105  		if imageMeta.Index.Index.Subject == nil {
   106  			return nil
   107  		}
   108  
   109  		return GetDescriptorRef(imageMeta.Index.Index.Subject)
   110  	default:
   111  		return nil
   112  	}
   113  }
   114  
   115  func GetDescriptorRef(descriptor *proto_go.Descriptor) *ispec.Descriptor {
   116  	if descriptor == nil {
   117  		return nil
   118  	}
   119  
   120  	platform := GetPlatformRef(descriptor.Platform)
   121  
   122  	return &ispec.Descriptor{
   123  		MediaType:    descriptor.MediaType,
   124  		Digest:       godigest.Digest(descriptor.Digest),
   125  		Size:         descriptor.Size,
   126  		URLs:         descriptor.URLs,
   127  		Data:         descriptor.Data,
   128  		Platform:     platform,
   129  		ArtifactType: deref(descriptor.ArtifactType, ""),
   130  		Annotations:  descriptor.Annotations,
   131  	}
   132  }
   133  
   134  func GetPlatform(platform *proto_go.Platform) ispec.Platform {
   135  	if platform == nil {
   136  		return ispec.Platform{}
   137  	}
   138  
   139  	return ispec.Platform{
   140  		Architecture: platform.Architecture,
   141  		OS:           platform.OS,
   142  		OSVersion:    deref(platform.OSVersion, ""),
   143  		OSFeatures:   platform.OSFeatures,
   144  		Variant:      deref(platform.Variant, ""),
   145  	}
   146  }
   147  
   148  func GetPlatformRef(platform *proto_go.Platform) *ispec.Platform {
   149  	if platform == nil {
   150  		return nil
   151  	}
   152  
   153  	return &ispec.Platform{
   154  		Architecture: platform.Architecture,
   155  		OS:           platform.OS,
   156  		OSVersion:    deref(platform.OSVersion, ""),
   157  		OSFeatures:   platform.OSFeatures,
   158  		Variant:      deref(platform.Variant, ""),
   159  	}
   160  }
   161  
   162  func GetLayers(descriptors []*proto_go.Descriptor) []ispec.Descriptor {
   163  	results := make([]ispec.Descriptor, 0, len(descriptors))
   164  
   165  	for _, desc := range descriptors {
   166  		results = append(results, ispec.Descriptor{
   167  			MediaType: desc.MediaType,
   168  			Digest:    godigest.Digest(desc.Digest),
   169  			Size:      desc.Size,
   170  		})
   171  	}
   172  
   173  	return results
   174  }
   175  
   176  func GetSubject(subj *proto_go.Descriptor) *ispec.Descriptor {
   177  	if subj == nil {
   178  		return nil
   179  	}
   180  
   181  	return &ispec.Descriptor{
   182  		MediaType: subj.MediaType,
   183  		Digest:    godigest.Digest(subj.Digest),
   184  		Size:      subj.Size,
   185  	}
   186  }
   187  
   188  func GetReferrers(refs map[string]*proto_go.ReferrersInfo) map[string][]mTypes.ReferrerInfo {
   189  	results := map[string][]mTypes.ReferrerInfo{}
   190  
   191  	for digest, ref := range refs {
   192  		referrers := []mTypes.ReferrerInfo{}
   193  
   194  		for _, dbRef := range ref.List {
   195  			referrers = append(referrers, mTypes.ReferrerInfo{
   196  				Digest:       dbRef.Digest,
   197  				MediaType:    dbRef.MediaType,
   198  				ArtifactType: dbRef.ArtifactType,
   199  				Size:         int(dbRef.Size),
   200  				Annotations:  dbRef.Annotations,
   201  			})
   202  		}
   203  
   204  		results[digest] = referrers
   205  	}
   206  
   207  	return results
   208  }
   209  
   210  func GetImageReferrers(refs *proto_go.ReferrersInfo) []mTypes.ReferrerInfo {
   211  	if refs == nil {
   212  		return []mTypes.ReferrerInfo{}
   213  	}
   214  
   215  	results := []mTypes.ReferrerInfo{}
   216  
   217  	for _, dbRef := range refs.List {
   218  		results = append(results, mTypes.ReferrerInfo{
   219  			Digest:       dbRef.Digest,
   220  			MediaType:    dbRef.MediaType,
   221  			ArtifactType: dbRef.ArtifactType,
   222  			Size:         int(dbRef.Size),
   223  			Annotations:  dbRef.Annotations,
   224  		})
   225  	}
   226  
   227  	return results
   228  }
   229  
   230  func GetSignatures(sigs map[string]*proto_go.ManifestSignatures) map[string]mTypes.ManifestSignatures {
   231  	results := map[string]mTypes.ManifestSignatures{}
   232  
   233  	for digest, dbSignatures := range sigs {
   234  		imageSignatures := mTypes.ManifestSignatures{}
   235  
   236  		for signatureName, signatureInfo := range dbSignatures.Map {
   237  			imageSignatures[signatureName] = GetSignaturesInfo(signatureInfo.List)
   238  		}
   239  
   240  		results[digest] = imageSignatures
   241  	}
   242  
   243  	return results
   244  }
   245  
   246  func GetImageSignatures(sigs *proto_go.ManifestSignatures) mTypes.ManifestSignatures {
   247  	if sigs == nil {
   248  		return mTypes.ManifestSignatures{}
   249  	}
   250  
   251  	results := mTypes.ManifestSignatures{}
   252  
   253  	for signatureName, signatureInfo := range sigs.Map {
   254  		results[signatureName] = GetSignaturesInfo(signatureInfo.List)
   255  	}
   256  
   257  	return results
   258  }
   259  
   260  func GetSignaturesInfo(sigsInfo []*proto_go.SignatureInfo) []mTypes.SignatureInfo {
   261  	results := []mTypes.SignatureInfo{}
   262  
   263  	for _, siginfo := range sigsInfo {
   264  		results = append(results, mTypes.SignatureInfo{
   265  			SignatureManifestDigest: siginfo.SignatureManifestDigest,
   266  			LayersInfo:              GetLayersInfo(siginfo.LayersInfo),
   267  		})
   268  	}
   269  
   270  	return results
   271  }
   272  
   273  func GetLayersInfo(layersInfo []*proto_go.LayersInfo) []mTypes.LayerInfo {
   274  	results := []mTypes.LayerInfo{}
   275  
   276  	for _, layerInfo := range layersInfo {
   277  		date := time.Time{}
   278  
   279  		if layerInfo.Date != nil {
   280  			date = layerInfo.Date.AsTime()
   281  		}
   282  
   283  		results = append(results, mTypes.LayerInfo{
   284  			LayerDigest:  layerInfo.LayerDigest,
   285  			LayerContent: layerInfo.LayerContent,
   286  			SignatureKey: layerInfo.SignatureKey,
   287  			Signer:       layerInfo.Signer,
   288  			Date:         date,
   289  		})
   290  	}
   291  
   292  	return results
   293  }
   294  
   295  func GetStatisticsMap(stats map[string]*proto_go.DescriptorStatistics) map[string]mTypes.DescriptorStatistics {
   296  	results := map[string]mTypes.DescriptorStatistics{}
   297  
   298  	for digest, stat := range stats {
   299  		results[digest] = mTypes.DescriptorStatistics{
   300  			DownloadCount:     int(stat.DownloadCount),
   301  			LastPullTimestamp: stat.LastPullTimestamp.AsTime(),
   302  			PushTimestamp:     stat.PushTimestamp.AsTime(),
   303  			PushedBy:          stat.PushedBy,
   304  		}
   305  	}
   306  
   307  	return results
   308  }
   309  
   310  func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics {
   311  	if stats == nil {
   312  		return mTypes.DescriptorStatistics{}
   313  	}
   314  
   315  	return mTypes.DescriptorStatistics{
   316  		DownloadCount:     int(stats.DownloadCount),
   317  		LastPullTimestamp: stats.LastPullTimestamp.AsTime(),
   318  		PushTimestamp:     stats.PushTimestamp.AsTime(),
   319  		PushedBy:          stats.PushedBy,
   320  	}
   321  }
   322  
   323  func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64,
   324  	digest godigest.Digest,
   325  ) mTypes.ImageMeta {
   326  	return mTypes.ImageMeta{
   327  		MediaType: ispec.MediaTypeImageManifest,
   328  		Digest:    digest,
   329  		Size:      size,
   330  		Manifests: []mTypes.ManifestMeta{
   331  			{
   332  				Digest:   digest,
   333  				Size:     size,
   334  				Config:   configContent,
   335  				Manifest: manifestContent,
   336  			},
   337  		},
   338  	}
   339  }
   340  
   341  func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta {
   342  	return mTypes.ImageMeta{
   343  		MediaType: ispec.MediaTypeImageIndex,
   344  		Index:     &indexContent,
   345  		Manifests: GetManifests(indexContent.Manifests),
   346  		Size:      size,
   347  		Digest:    digest,
   348  	}
   349  }
   350  
   351  func GetTags(tags map[string]*proto_go.TagDescriptor) map[string]mTypes.Descriptor {
   352  	resultMap := map[string]mTypes.Descriptor{}
   353  
   354  	for tag, tagDescriptor := range tags {
   355  		resultMap[tag] = mTypes.Descriptor{
   356  			Digest:    tagDescriptor.Digest,
   357  			MediaType: tagDescriptor.MediaType,
   358  		}
   359  	}
   360  
   361  	return resultMap
   362  }
   363  
   364  func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestMeta {
   365  	manifestList := []mTypes.ManifestMeta{}
   366  
   367  	for _, manifest := range descriptors {
   368  		manifestList = append(manifestList, mTypes.ManifestMeta{
   369  			Digest: manifest.Digest,
   370  			Size:   manifest.Size,
   371  		})
   372  	}
   373  
   374  	return manifestList
   375  }
   376  
   377  func GetTime(time *timestamppb.Timestamp) *time.Time {
   378  	if time == nil {
   379  		return nil
   380  	}
   381  
   382  	return ref(time.AsTime())
   383  }
   384  
   385  func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta,
   386  ) mTypes.FullImageMeta {
   387  	if protoRepoMeta == nil {
   388  		return mTypes.FullImageMeta{}
   389  	}
   390  
   391  	imageMeta := GetImageMeta(protoImageMeta)
   392  	imageDigest := imageMeta.Digest.String()
   393  
   394  	return mTypes.FullImageMeta{
   395  		Repo:         protoRepoMeta.Name,
   396  		Tag:          tag,
   397  		MediaType:    imageMeta.MediaType,
   398  		Digest:       imageMeta.Digest,
   399  		Size:         imageMeta.Size,
   400  		Index:        imageMeta.Index,
   401  		Manifests:    GetFullManifestData(protoRepoMeta, imageMeta.Manifests),
   402  		IsStarred:    protoRepoMeta.IsStarred,
   403  		IsBookmarked: protoRepoMeta.IsBookmarked,
   404  
   405  		Referrers:  GetImageReferrers(protoRepoMeta.Referrers[imageDigest]),
   406  		Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]),
   407  		Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]),
   408  	}
   409  }
   410  
   411  func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestMeta,
   412  ) []mTypes.FullManifestMeta {
   413  	if protoRepoMeta == nil {
   414  		return []mTypes.FullManifestMeta{}
   415  	}
   416  
   417  	results := []mTypes.FullManifestMeta{}
   418  
   419  	for i := range manifestData {
   420  		results = append(results, mTypes.FullManifestMeta{
   421  			ManifestMeta: manifestData[i],
   422  			Referrers:    GetImageReferrers(protoRepoMeta.Referrers[manifestData[i].Digest.String()]),
   423  			Statistics:   GetImageStatistics(protoRepoMeta.Statistics[manifestData[i].Digest.String()]),
   424  			Signatures:   GetImageSignatures(protoRepoMeta.Signatures[manifestData[i].Digest.String()]),
   425  		})
   426  	}
   427  
   428  	return results
   429  }
   430  
   431  func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta {
   432  	if protoRepoMeta == nil {
   433  		return mTypes.RepoMeta{}
   434  	}
   435  
   436  	repoDownloads := int32(0)
   437  
   438  	for _, descriptor := range protoRepoMeta.Tags {
   439  		if statistic := protoRepoMeta.Statistics[descriptor.Digest]; statistic != nil {
   440  			repoDownloads += statistic.DownloadCount
   441  		}
   442  	}
   443  
   444  	return mTypes.RepoMeta{
   445  		Name:             protoRepoMeta.Name,
   446  		Tags:             GetTags(protoRepoMeta.Tags),
   447  		Rank:             int(protoRepoMeta.Rank),
   448  		Size:             int64(protoRepoMeta.Size),
   449  		Platforms:        GetPlatforms(protoRepoMeta.Platforms),
   450  		Vendors:          protoRepoMeta.Vendors,
   451  		IsStarred:        protoRepoMeta.IsStarred,
   452  		IsBookmarked:     protoRepoMeta.IsBookmarked,
   453  		StarCount:        int(protoRepoMeta.Stars),
   454  		DownloadCount:    int(repoDownloads),
   455  		LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.LastUpdatedImage),
   456  		Statistics:       GetStatisticsMap(protoRepoMeta.Statistics),
   457  		Signatures:       GetSignatures(protoRepoMeta.Signatures),
   458  		Referrers:        GetReferrers(protoRepoMeta.Referrers),
   459  	}
   460  }
   461  
   462  func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform {
   463  	result := []ispec.Platform{}
   464  
   465  	for i := range platforms {
   466  		result = append(result, GetPlatform(platforms[i]))
   467  	}
   468  
   469  	return result
   470  }
   471  
   472  func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform {
   473  	for _, newPlatform := range newPlatforms {
   474  		if !ContainsProtoPlatform(platforms, newPlatform) {
   475  			platforms = append(platforms, newPlatform)
   476  		}
   477  	}
   478  
   479  	return platforms
   480  }
   481  
   482  func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool {
   483  	for i := range platforms {
   484  		if platforms[i].OS == platform.OS && platforms[i].Architecture == platform.Architecture {
   485  			return true
   486  		}
   487  	}
   488  
   489  	return false
   490  }
   491  
   492  func AddVendors(vendors []string, newVendors []string) []string {
   493  	for _, newVendor := range newVendors {
   494  		if !common.Contains(vendors, newVendor) {
   495  			vendors = append(vendors, newVendor)
   496  		}
   497  	}
   498  
   499  	return vendors
   500  }
   501  
   502  func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage {
   503  	if protoLastUpdated == nil {
   504  		return nil
   505  	}
   506  
   507  	return &mTypes.LastUpdatedImage{
   508  		Descriptor: mTypes.Descriptor{
   509  			Digest:    protoLastUpdated.Digest,
   510  			MediaType: protoLastUpdated.MediaType,
   511  		},
   512  		Tag:         protoLastUpdated.Tag,
   513  		LastUpdated: GetTime(protoLastUpdated.LastUpdated),
   514  	}
   515  }
   516  
   517  func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta {
   518  	if dbImageMeta == nil {
   519  		return mTypes.ImageMeta{}
   520  	}
   521  
   522  	imageMeta := mTypes.ImageMeta{
   523  		MediaType: dbImageMeta.MediaType,
   524  		Size:      GetImageManifestSize(dbImageMeta),
   525  		Digest:    GetImageDigest(dbImageMeta),
   526  	}
   527  
   528  	if dbImageMeta.MediaType == ispec.MediaTypeImageIndex {
   529  		manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests))
   530  
   531  		for _, manifest := range dbImageMeta.Manifests {
   532  			manifests = append(manifests, ispec.Descriptor{
   533  				MediaType: deref(manifest.Manifest.MediaType, ""),
   534  				Digest:    godigest.Digest(manifest.Digest),
   535  				Size:      manifest.Size,
   536  			})
   537  		}
   538  
   539  		imageMeta.Index = &ispec.Index{
   540  			Versioned:    specs.Versioned{SchemaVersion: int(dbImageMeta.Index.Index.Versioned.GetSchemaVersion())},
   541  			MediaType:    ispec.MediaTypeImageIndex,
   542  			Manifests:    manifests,
   543  			Subject:      GetImageSubject(dbImageMeta),
   544  			ArtifactType: GetImageArtifactType(dbImageMeta),
   545  			Annotations:  GetImageAnnotations(dbImageMeta),
   546  		}
   547  	}
   548  
   549  	manifestDataList := make([]mTypes.ManifestMeta, 0, len(dbImageMeta.Manifests))
   550  
   551  	for _, manifest := range dbImageMeta.Manifests {
   552  		manifestDataList = append(manifestDataList, mTypes.ManifestMeta{
   553  			Size:   manifest.Size,
   554  			Digest: godigest.Digest(manifest.Digest),
   555  			Manifest: ispec.Manifest{
   556  				Versioned:    specs.Versioned{SchemaVersion: int(manifest.Manifest.Versioned.GetSchemaVersion())},
   557  				MediaType:    deref(manifest.Manifest.MediaType, ""),
   558  				ArtifactType: deref(manifest.Manifest.ArtifactType, ""),
   559  				Config: ispec.Descriptor{
   560  					MediaType: manifest.Manifest.Config.MediaType,
   561  					Size:      manifest.Manifest.Config.Size,
   562  					Digest:    godigest.Digest(manifest.Manifest.Config.Digest),
   563  				},
   564  				Layers:      GetLayers(manifest.Manifest.Layers),
   565  				Subject:     GetSubject(manifest.Manifest.Subject),
   566  				Annotations: manifest.Manifest.Annotations,
   567  			},
   568  			Config: ispec.Image{
   569  				Created:  GetTime(manifest.Config.Created),
   570  				Author:   deref(manifest.Config.Author, ""),
   571  				Platform: GetPlatform(manifest.Config.Platform),
   572  				Config: ispec.ImageConfig{
   573  					User:         manifest.Config.Config.User,
   574  					ExposedPorts: GetExposedPorts(manifest.Config.Config.ExposedPorts),
   575  					Env:          manifest.Config.Config.Env,
   576  					Entrypoint:   manifest.Config.Config.Entrypoint,
   577  					Cmd:          manifest.Config.Config.Cmd,
   578  					Volumes:      GetConfigVolumes(manifest.Config.Config.Volumes),
   579  					WorkingDir:   deref(manifest.Config.Config.WorkingDir, ""),
   580  					Labels:       manifest.Config.Config.Labels,
   581  					StopSignal:   deref(manifest.Config.Config.StopSignal, ""),
   582  				},
   583  				RootFS: ispec.RootFS{
   584  					Type:    manifest.Config.RootFS.Type,
   585  					DiffIDs: GetDiffIDs(manifest.Config.RootFS.DiffIDs),
   586  				},
   587  				History: GetHistory(manifest.Config.History),
   588  			},
   589  		})
   590  	}
   591  
   592  	imageMeta.Manifests = manifestDataList
   593  
   594  	return imageMeta
   595  }
   596  
   597  func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} {
   598  	if exposedPorts == nil {
   599  		return nil
   600  	}
   601  
   602  	result := map[string]struct{}{}
   603  
   604  	for key := range exposedPorts {
   605  		result[key] = struct{}{}
   606  	}
   607  
   608  	return result
   609  }
   610  
   611  func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} {
   612  	if configVolumes == nil {
   613  		return nil
   614  	}
   615  
   616  	result := map[string]struct{}{}
   617  
   618  	for key := range configVolumes {
   619  		result[key] = struct{}{}
   620  	}
   621  
   622  	return result
   623  }
   624  
   625  func GetDiffIDs(diffIDs []string) []godigest.Digest {
   626  	result := make([]godigest.Digest, 0, len(diffIDs))
   627  
   628  	for i := range diffIDs {
   629  		result = append(result, godigest.Digest(diffIDs[i]))
   630  	}
   631  
   632  	return result
   633  }