zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/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.dev/zot/pkg/common" 12 proto_go "zotregistry.dev/zot/pkg/meta/proto/gen" 13 mTypes "zotregistry.dev/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[mTypes.ImageDigest]*proto_go.DescriptorStatistics, 296 ) map[mTypes.ImageDigest]mTypes.DescriptorStatistics { 297 results := map[mTypes.ImageDigest]mTypes.DescriptorStatistics{} 298 299 for digest, stat := range stats { 300 results[digest] = mTypes.DescriptorStatistics{ 301 DownloadCount: int(stat.DownloadCount), 302 LastPullTimestamp: stat.LastPullTimestamp.AsTime(), 303 PushTimestamp: stat.PushTimestamp.AsTime(), 304 PushedBy: stat.PushedBy, 305 } 306 } 307 308 return results 309 } 310 311 func GetImageStatistics(stats *proto_go.DescriptorStatistics) mTypes.DescriptorStatistics { 312 if stats == nil { 313 return mTypes.DescriptorStatistics{} 314 } 315 316 return mTypes.DescriptorStatistics{ 317 DownloadCount: int(stats.DownloadCount), 318 LastPullTimestamp: stats.LastPullTimestamp.AsTime(), 319 PushTimestamp: stats.PushTimestamp.AsTime(), 320 PushedBy: stats.PushedBy, 321 } 322 } 323 324 func GetImageManifestMeta(manifestContent ispec.Manifest, configContent ispec.Image, size int64, 325 digest godigest.Digest, 326 ) mTypes.ImageMeta { 327 return mTypes.ImageMeta{ 328 MediaType: ispec.MediaTypeImageManifest, 329 Digest: digest, 330 Size: size, 331 Manifests: []mTypes.ManifestMeta{ 332 { 333 Digest: digest, 334 Size: size, 335 Config: configContent, 336 Manifest: manifestContent, 337 }, 338 }, 339 } 340 } 341 342 func GetImageIndexMeta(indexContent ispec.Index, size int64, digest godigest.Digest) mTypes.ImageMeta { 343 return mTypes.ImageMeta{ 344 MediaType: ispec.MediaTypeImageIndex, 345 Index: &indexContent, 346 Manifests: GetManifests(indexContent.Manifests), 347 Size: size, 348 Digest: digest, 349 } 350 } 351 352 func GetTags(tags map[mTypes.Tag]*proto_go.TagDescriptor) map[mTypes.Tag]mTypes.Descriptor { 353 resultMap := map[mTypes.Tag]mTypes.Descriptor{} 354 355 for tag, tagDescriptor := range tags { 356 resultMap[tag] = mTypes.Descriptor{ 357 Digest: tagDescriptor.Digest, 358 MediaType: tagDescriptor.MediaType, 359 } 360 } 361 362 return resultMap 363 } 364 365 func GetManifests(descriptors []ispec.Descriptor) []mTypes.ManifestMeta { 366 manifestList := []mTypes.ManifestMeta{} 367 368 for _, manifest := range descriptors { 369 manifestList = append(manifestList, mTypes.ManifestMeta{ 370 Digest: manifest.Digest, 371 Size: manifest.Size, 372 }) 373 } 374 375 return manifestList 376 } 377 378 func GetTime(time *timestamppb.Timestamp) *time.Time { 379 if time == nil { 380 return nil 381 } 382 383 return ref(time.AsTime()) 384 } 385 386 func GetFullImageMetaFromProto(tag string, protoRepoMeta *proto_go.RepoMeta, protoImageMeta *proto_go.ImageMeta, 387 ) mTypes.FullImageMeta { 388 if protoRepoMeta == nil { 389 return mTypes.FullImageMeta{} 390 } 391 392 imageMeta := GetImageMeta(protoImageMeta) 393 imageDigest := imageMeta.Digest.String() 394 395 return mTypes.FullImageMeta{ 396 Repo: protoRepoMeta.Name, 397 Tag: tag, 398 MediaType: imageMeta.MediaType, 399 Digest: imageMeta.Digest, 400 Size: imageMeta.Size, 401 Index: imageMeta.Index, 402 Manifests: GetFullManifestData(protoRepoMeta, imageMeta.Manifests), 403 IsStarred: protoRepoMeta.IsStarred, 404 IsBookmarked: protoRepoMeta.IsBookmarked, 405 406 Referrers: GetImageReferrers(protoRepoMeta.Referrers[imageDigest]), 407 Statistics: GetImageStatistics(protoRepoMeta.Statistics[imageDigest]), 408 Signatures: GetImageSignatures(protoRepoMeta.Signatures[imageDigest]), 409 } 410 } 411 412 func GetFullManifestData(protoRepoMeta *proto_go.RepoMeta, manifestData []mTypes.ManifestMeta, 413 ) []mTypes.FullManifestMeta { 414 if protoRepoMeta == nil { 415 return []mTypes.FullManifestMeta{} 416 } 417 418 results := []mTypes.FullManifestMeta{} 419 420 for i := range manifestData { 421 results = append(results, mTypes.FullManifestMeta{ 422 ManifestMeta: manifestData[i], 423 Referrers: GetImageReferrers(protoRepoMeta.Referrers[manifestData[i].Digest.String()]), 424 Statistics: GetImageStatistics(protoRepoMeta.Statistics[manifestData[i].Digest.String()]), 425 Signatures: GetImageSignatures(protoRepoMeta.Signatures[manifestData[i].Digest.String()]), 426 }) 427 } 428 429 return results 430 } 431 432 func GetRepoMeta(protoRepoMeta *proto_go.RepoMeta) mTypes.RepoMeta { 433 if protoRepoMeta == nil { 434 return mTypes.RepoMeta{} 435 } 436 437 repoDownloads := int32(0) 438 439 for _, descriptor := range protoRepoMeta.Tags { 440 if statistic := protoRepoMeta.Statistics[descriptor.Digest]; statistic != nil { 441 repoDownloads += statistic.DownloadCount 442 } 443 } 444 445 return mTypes.RepoMeta{ 446 Name: protoRepoMeta.Name, 447 Tags: GetTags(protoRepoMeta.Tags), 448 Rank: int(protoRepoMeta.Rank), 449 Size: protoRepoMeta.Size, 450 Platforms: GetPlatforms(protoRepoMeta.Platforms), 451 Vendors: protoRepoMeta.Vendors, 452 IsStarred: protoRepoMeta.IsStarred, 453 IsBookmarked: protoRepoMeta.IsBookmarked, 454 StarCount: int(protoRepoMeta.Stars), 455 DownloadCount: int(repoDownloads), 456 LastUpdatedImage: GetLastUpdatedImage(protoRepoMeta.LastUpdatedImage), 457 Statistics: GetStatisticsMap(protoRepoMeta.Statistics), 458 Signatures: GetSignatures(protoRepoMeta.Signatures), 459 Referrers: GetReferrers(protoRepoMeta.Referrers), 460 } 461 } 462 463 func GetPlatforms(platforms []*proto_go.Platform) []ispec.Platform { 464 result := []ispec.Platform{} 465 466 for i := range platforms { 467 result = append(result, GetPlatform(platforms[i])) 468 } 469 470 return result 471 } 472 473 func AddProtoPlatforms(platforms []*proto_go.Platform, newPlatforms []*proto_go.Platform) []*proto_go.Platform { 474 for _, newPlatform := range newPlatforms { 475 if !ContainsProtoPlatform(platforms, newPlatform) { 476 platforms = append(platforms, newPlatform) 477 } 478 } 479 480 return platforms 481 } 482 483 func ContainsProtoPlatform(platforms []*proto_go.Platform, platform *proto_go.Platform) bool { 484 for i := range platforms { 485 if platforms[i].OS == platform.OS && platforms[i].Architecture == platform.Architecture { 486 return true 487 } 488 } 489 490 return false 491 } 492 493 func AddVendors(vendors []string, newVendors []string) []string { 494 for _, newVendor := range newVendors { 495 if !common.Contains(vendors, newVendor) { 496 vendors = append(vendors, newVendor) 497 } 498 } 499 500 return vendors 501 } 502 503 func GetLastUpdatedImage(protoLastUpdated *proto_go.RepoLastUpdatedImage) *mTypes.LastUpdatedImage { 504 if protoLastUpdated == nil { 505 return nil 506 } 507 508 return &mTypes.LastUpdatedImage{ 509 Descriptor: mTypes.Descriptor{ 510 Digest: protoLastUpdated.Digest, 511 MediaType: protoLastUpdated.MediaType, 512 }, 513 Tag: protoLastUpdated.Tag, 514 LastUpdated: GetTime(protoLastUpdated.LastUpdated), 515 } 516 } 517 518 func GetImageMeta(dbImageMeta *proto_go.ImageMeta) mTypes.ImageMeta { 519 if dbImageMeta == nil { 520 return mTypes.ImageMeta{} 521 } 522 523 imageMeta := mTypes.ImageMeta{ 524 MediaType: dbImageMeta.MediaType, 525 Size: GetImageManifestSize(dbImageMeta), 526 Digest: GetImageDigest(dbImageMeta), 527 } 528 529 if dbImageMeta.MediaType == ispec.MediaTypeImageIndex { 530 manifests := make([]ispec.Descriptor, 0, len(dbImageMeta.Manifests)) 531 532 for _, manifest := range deref(dbImageMeta.Index, proto_go.IndexMeta{}).Index.Manifests { 533 manifests = append(manifests, ispec.Descriptor{ 534 MediaType: manifest.MediaType, 535 Digest: godigest.Digest(manifest.Digest), 536 Size: manifest.Size, 537 }) 538 } 539 540 imageMeta.Index = &ispec.Index{ 541 Versioned: specs.Versioned{SchemaVersion: int(dbImageMeta.Index.Index.Versioned.GetSchemaVersion())}, 542 MediaType: ispec.MediaTypeImageIndex, 543 Manifests: manifests, 544 Subject: GetImageSubject(dbImageMeta), 545 ArtifactType: GetImageArtifactType(dbImageMeta), 546 Annotations: GetImageAnnotations(dbImageMeta), 547 } 548 } 549 550 manifestDataList := make([]mTypes.ManifestMeta, 0, len(dbImageMeta.Manifests)) 551 552 for _, manifest := range dbImageMeta.Manifests { 553 manifestDataList = append(manifestDataList, mTypes.ManifestMeta{ 554 Size: manifest.Size, 555 Digest: godigest.Digest(manifest.Digest), 556 Manifest: ispec.Manifest{ 557 Versioned: specs.Versioned{SchemaVersion: int(manifest.Manifest.Versioned.GetSchemaVersion())}, 558 MediaType: deref(manifest.Manifest.MediaType, ""), 559 ArtifactType: deref(manifest.Manifest.ArtifactType, ""), 560 Config: ispec.Descriptor{ 561 MediaType: manifest.Manifest.Config.MediaType, 562 Size: manifest.Manifest.Config.Size, 563 Digest: godigest.Digest(manifest.Manifest.Config.Digest), 564 }, 565 Layers: GetLayers(manifest.Manifest.Layers), 566 Subject: GetSubject(manifest.Manifest.Subject), 567 Annotations: manifest.Manifest.Annotations, 568 }, 569 Config: ispec.Image{ 570 Created: GetTime(manifest.Config.Created), 571 Author: deref(manifest.Config.Author, ""), 572 Platform: GetPlatform(manifest.Config.Platform), 573 Config: ispec.ImageConfig{ 574 User: manifest.Config.Config.User, 575 ExposedPorts: GetExposedPorts(manifest.Config.Config.ExposedPorts), 576 Env: manifest.Config.Config.Env, 577 Entrypoint: manifest.Config.Config.Entrypoint, 578 Cmd: manifest.Config.Config.Cmd, 579 Volumes: GetConfigVolumes(manifest.Config.Config.Volumes), 580 WorkingDir: deref(manifest.Config.Config.WorkingDir, ""), 581 Labels: manifest.Config.Config.Labels, 582 StopSignal: deref(manifest.Config.Config.StopSignal, ""), 583 }, 584 RootFS: ispec.RootFS{ 585 Type: manifest.Config.RootFS.Type, 586 DiffIDs: GetDiffIDs(manifest.Config.RootFS.DiffIDs), 587 }, 588 History: GetHistory(manifest.Config.History), 589 }, 590 }) 591 } 592 593 imageMeta.Manifests = manifestDataList 594 595 return imageMeta 596 } 597 598 func GetExposedPorts(exposedPorts map[string]*proto_go.EmptyMessage) map[string]struct{} { 599 if exposedPorts == nil { 600 return nil 601 } 602 603 result := map[string]struct{}{} 604 605 for key := range exposedPorts { 606 result[key] = struct{}{} 607 } 608 609 return result 610 } 611 612 func GetConfigVolumes(configVolumes map[string]*proto_go.EmptyMessage) map[string]struct{} { 613 if configVolumes == nil { 614 return nil 615 } 616 617 result := map[string]struct{}{} 618 619 for key := range configVolumes { 620 result[key] = struct{}{} 621 } 622 623 return result 624 } 625 626 func GetDiffIDs(diffIDs []string) []godigest.Digest { 627 result := make([]godigest.Digest, 0, len(diffIDs)) 628 629 for i := range diffIDs { 630 result = append(result, godigest.Digest(diffIDs[i])) 631 } 632 633 return result 634 }