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 }