Skip to content

Commit 8d37bc1

Browse files
committed
Optimize-virtual-repo-layer-filtering
1 parent 60a3b4b commit 8d37bc1

File tree

1 file changed

+94
-4
lines changed

1 file changed

+94
-4
lines changed

artifactory/utils/container/buildinfo.go

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package container
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"os"
67
"path"
78
"strings"
@@ -91,7 +92,7 @@ func (builder *buildInfoBuilder) getSearchableRepo() string {
9192
}
9293

9394
// Set build properties on image layers in Artifactory.
94-
func setBuildProperties(buildName, buildNumber, project string, imageLayers []utils.ResultItem, serviceManager artifactory.ArtifactoryServicesManager) (err error) {
95+
func setBuildProperties(buildName, buildNumber, project string, imageLayers []utils.ResultItem, serviceManager artifactory.ArtifactoryServicesManager, originalRepo string) (err error) {
9596
// Skip if no build info is provided
9697
if buildName == "" || buildNumber == "" {
9798
log.Debug("Skipping setting properties - build name and build number are required")
@@ -109,7 +110,14 @@ func setBuildProperties(buildName, buildNumber, project string, imageLayers []ut
109110
return nil
110111
}
111112

112-
pathToFile, err := writeLayersToFile(imageLayers)
113+
// Filter image layers for virtual repositories to only include layers from default deployment repository
114+
filteredLayers, err := filterLayersForVirtualRepository(imageLayers, serviceManager, originalRepo)
115+
if err != nil {
116+
log.Debug("Failed to filter layers for virtual repository, proceeding with all layers:", err.Error())
117+
filteredLayers = imageLayers
118+
}
119+
120+
pathToFile, err := writeLayersToFile(filteredLayers)
113121
if err != nil {
114122
return
115123
}
@@ -119,6 +127,88 @@ func setBuildProperties(buildName, buildNumber, project string, imageLayers []ut
119127
return
120128
}
121129

130+
// filterLayersForVirtualRepository filters image layers to only include those from the default deployment repository
131+
// when dealing with virtual repositories. For non-virtual repositories, it returns all layers unchanged.
132+
func filterLayersForVirtualRepository(imageLayers []utils.ResultItem, serviceManager artifactory.ArtifactoryServicesManager, originalRepo string) ([]utils.ResultItem, error) {
133+
if len(imageLayers) == 0 {
134+
return imageLayers, nil
135+
}
136+
137+
// Check if the original repository is a virtual repository by getting its configuration
138+
repoConfig, err := getRepositoryConfiguration(originalRepo, serviceManager)
139+
if err != nil {
140+
log.Debug("Failed to get repository configuration for", originalRepo, ":", err.Error())
141+
return imageLayers, err
142+
}
143+
144+
// If it's not a virtual repository, return all layers unchanged
145+
if repoConfig == nil || repoConfig.Rclass != "virtual" {
146+
log.Debug("Repository", originalRepo, "is not virtual, proceeding with all layers")
147+
return imageLayers, nil
148+
}
149+
150+
// If it's a virtual repository but has no default deployment repo, return all layers
151+
if repoConfig.DefaultDeploymentRepo == "" {
152+
log.Debug("Virtual repository", originalRepo, "has no default deployment repository, proceeding with all layers")
153+
return imageLayers, nil
154+
}
155+
156+
// Filter layers to only include those from the default deployment repository
157+
var filteredLayers []utils.ResultItem
158+
for _, layer := range imageLayers {
159+
if layer.Repo == repoConfig.DefaultDeploymentRepo {
160+
filteredLayers = append(filteredLayers, layer)
161+
}
162+
}
163+
164+
if len(filteredLayers) > 0 {
165+
log.Debug("Filtered", len(imageLayers), "layers to", len(filteredLayers), "layers from default deployment repository:", repoConfig.DefaultDeploymentRepo)
166+
} else {
167+
log.Debug("No layers found in default deployment repository", repoConfig.DefaultDeploymentRepo, ", proceeding with all layers")
168+
return imageLayers, nil
169+
}
170+
171+
return filteredLayers, nil
172+
}
173+
174+
// repositoryConfig represents the virtual repository configuration
175+
type
176+
struct {
177+
Key string `json:"key"`
178+
Rclass string `json:"rclass"`
179+
DefaultDeploymentRepo string `json:"defaultDeploymentRepo"`
180+
}
181+
182+
// getRepositoryConfiguration fetches the repository configuration from Artifactory
183+
func getRepositoryConfiguration(repoKey string, serviceManager artifactory.ArtifactoryServicesManager) (*repositoryConfig, error) {
184+
// Create HTTP client details for the request
185+
httpClientDetails := serviceManager.GetConfig().GetServiceDetails().CreateHttpClientDetails()
186+
187+
// Construct the API endpoint URL
188+
baseUrl := serviceManager.GetConfig().GetServiceDetails().GetUrl()
189+
endpoint := "api/repositories/" + repoKey
190+
url := baseUrl + endpoint
191+
192+
// Make the HTTP GET request
193+
resp, body, _, err := serviceManager.Client().SendGet(url, true, &httpClientDetails)
194+
if err != nil {
195+
return nil, err
196+
}
197+
198+
// Check for successful response
199+
if resp.StatusCode != 200 {
200+
return nil, fmt.Errorf("failed to get repository configuration: HTTP %d", resp.StatusCode)
201+
}
202+
203+
// Parse the JSON response
204+
var config repositoryConfig
205+
if err := json.Unmarshal(body, &config); err != nil {
206+
return nil, fmt.Errorf("failed to parse repository configuration: %v", err)
207+
}
208+
209+
return &config, nil
210+
}
211+
122212
// Download the content of layer search result.
123213
func downloadLayer(searchResult utils.ResultItem, result interface{}, serviceManager artifactory.ArtifactoryServicesManager, repo string) error {
124214
// Search results may include artifacts from the remote-cache repository.
@@ -340,7 +430,7 @@ func (builder *buildInfoBuilder) createBuildInfo(commandType CommandType, manife
340430
return nil, err
341431
}
342432
if !builder.skipTaggingLayers {
343-
if err := setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager); err != nil {
433+
if err := setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager, builder.repositoryDetails.key); err != nil {
344434
return nil, err
345435
}
346436
}
@@ -399,7 +489,7 @@ func (builder *buildInfoBuilder) createMultiPlatformBuildInfo(fatManifest *FatMa
399489
Parent: imageLongNameWithoutRepo,
400490
})
401491
}
402-
return buildInfo, setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager)
492+
return buildInfo, setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager, builder.repositoryDetails.key)
403493
}
404494

405495
// Construct the manifest's module ID by its type (attestation) or its platform.

0 commit comments

Comments
 (0)