github.com/jfrog/jfrog-cli-core/v2@v2.52.0/artifactory/utils/container/remoteagent.go (about) 1 package container 2 3 import ( 4 "strings" 5 6 buildinfo "github.com/jfrog/build-info-go/entities" 7 "github.com/jfrog/jfrog-client-go/artifactory" 8 "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 9 "github.com/jfrog/jfrog-client-go/utils/errorutils" 10 "github.com/jfrog/jfrog-client-go/utils/log" 11 ) 12 13 // Build-info builder for remote agents tools such as: Kaniko, OpenShift CLI (oc), or buildx. 14 type RemoteAgentBuildInfoBuilder struct { 15 buildInfoBuilder *buildInfoBuilder 16 manifestSha2 string 17 } 18 19 func NewRemoteAgentBuildInfoBuilder(image *Image, repository, buildName, buildNumber, project string, serviceManager artifactory.ArtifactoryServicesManager, manifestSha256 string) (*RemoteAgentBuildInfoBuilder, error) { 20 builder, err := newBuildInfoBuilder(image, repository, buildName, buildNumber, project, serviceManager) 21 return &RemoteAgentBuildInfoBuilder{ 22 buildInfoBuilder: builder, 23 manifestSha2: manifestSha256, 24 }, err 25 } 26 27 func (rabib *RemoteAgentBuildInfoBuilder) GetLayers() *[]utils.ResultItem { 28 return &rabib.buildInfoBuilder.imageLayers 29 } 30 31 func (rabib *RemoteAgentBuildInfoBuilder) Build(module string) (*buildinfo.BuildInfo, error) { 32 // Search for and image in Artifactory. 33 results, err := rabib.searchImage() 34 if err != nil { 35 return nil, err 36 } 37 // Create build-info based on image manifest. 38 if results["manifest.json"] != nil { 39 searchResults, manifest, err := rabib.handleManifest(results) 40 if err != nil { 41 return nil, err 42 } 43 return rabib.buildInfoBuilder.createBuildInfo(Push, manifest, searchResults, module) 44 } 45 // Create build-info based on image fat-manifest. 46 multiPlatformImages, fatManifestDetails, fatManifest, err := rabib.handleFatManifestImage(results) 47 if err != nil { 48 return nil, err 49 } 50 return rabib.buildInfoBuilder.createMultiPlatformBuildInfo(fatManifest, fatManifestDetails, multiPlatformImages, module) 51 } 52 53 // Search for image manifest and layers in Artifactory. 54 func (rabib *RemoteAgentBuildInfoBuilder) handleManifest(resultMap map[string]*utils.ResultItem) (map[string]*utils.ResultItem, *manifest, error) { 55 if manifest, ok := resultMap["manifest.json"]; ok { 56 err := rabib.isVerifiedManifest(manifest) 57 if err != nil { 58 return nil, nil, err 59 60 } 61 manifest, err := getManifest(resultMap, rabib.buildInfoBuilder.serviceManager, rabib.buildInfoBuilder.repositoryDetails.key) 62 if err != nil { 63 return nil, nil, err 64 } 65 // // Manifest may hold 'empty layers'. As a result, promotion will fail to promote the same layer more than once. 66 rabib.buildInfoBuilder.imageSha2 = manifest.Config.Digest 67 log.Debug("Found manifest.json. Proceeding to create build-info.") 68 return resultMap, manifest, nil 69 } 70 return nil, nil, errorutils.CheckErrorf(`couldn't find image "` + rabib.buildInfoBuilder.image.name + `" manifest in Artifactory`) 71 } 72 73 func (rabib *RemoteAgentBuildInfoBuilder) handleFatManifestImage(results map[string]*utils.ResultItem) (map[string][]*utils.ResultItem, *utils.ResultItem, *FatManifest, error) { 74 if fatManifestResult, ok := results["list.manifest.json"]; ok { 75 log.Debug("Found list.manifest.json. Proceeding to create build-info.") 76 fatManifestRootPath := getFatManifestRoot(fatManifestResult.GetItemRelativeLocation()) + "/*" 77 fatManifest, err := getFatManifest(results, rabib.buildInfoBuilder.serviceManager, rabib.buildInfoBuilder.repositoryDetails.key) 78 if err != nil { 79 return nil, nil, nil, err 80 } 81 multiPlatformImages, err := performMultiPlatformImageSearch(fatManifestRootPath, rabib.buildInfoBuilder.serviceManager) 82 return multiPlatformImages, fatManifestResult, fatManifest, err 83 } 84 return nil, nil, nil, errorutils.CheckErrorf(`couldn't find image "` + rabib.buildInfoBuilder.image.name + `" fat manifest in Artifactory`) 85 } 86 87 // Search image manifest or fat-manifest of and image. 88 func (rabib *RemoteAgentBuildInfoBuilder) searchImage() (resultMap map[string]*utils.ResultItem, err error) { 89 longImageName, err := rabib.buildInfoBuilder.image.GetImageLongNameWithTag() 90 if err != nil { 91 return nil, err 92 } 93 imagePath := strings.Replace(longImageName, ":", "/", 1) 94 95 // Search image's manifest. 96 manifestPathsCandidates := getManifestPaths(imagePath, rabib.buildInfoBuilder.getSearchableRepo(), Push) 97 log.Debug("Start searching for image manifest.json") 98 for _, path := range manifestPathsCandidates { 99 log.Debug(`Searching in:"` + path + `"`) 100 resultMap, err = performSearch(path, rabib.buildInfoBuilder.serviceManager) 101 if err != nil { 102 return nil, err 103 } 104 if resultMap == nil { 105 continue 106 } 107 if resultMap["list.manifest.json"] != nil || resultMap["manifest.json"] != nil { 108 return resultMap, nil 109 } 110 } 111 return nil, errorutils.CheckErrorf(imageNotFoundErrorMessage, rabib.buildInfoBuilder.image.name) 112 } 113 114 // Verify manifest's sha256. If there is no match, return nil. 115 func (rabib *RemoteAgentBuildInfoBuilder) isVerifiedManifest(imageManifest *utils.ResultItem) error { 116 if imageManifest.GetProperty("docker.manifest.digest") != rabib.manifestSha2 { 117 return errorutils.CheckErrorf(`Found incorrect manifest.json file. Expects digest "` + rabib.manifestSha2 + `" found "` + imageManifest.GetProperty("docker.manifest.digest")) 118 } 119 return nil 120 } 121 122 func getFatManifestRoot(fatManifestPath string) string { 123 fatManifestPath = strings.TrimSuffix(fatManifestPath, "/") 124 return fatManifestPath[:strings.LastIndex(fatManifestPath, "/")] 125 }