Skip to content

Commit 96fe58b

Browse files
committed
Optimize-virtual-repo-layer-filtering
1 parent 60a3b4b commit 96fe58b

File tree

1 file changed

+93
-4
lines changed

1 file changed

+93
-4
lines changed

artifactory/utils/container/buildinfo.go

Lines changed: 93 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,87 @@ 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 repositoryConfig struct {
176+
Key string `json:"key"`
177+
Rclass string `json:"rclass"`
178+
DefaultDeploymentRepo string `json:"defaultDeploymentRepo"`
179+
}
180+
181+
// getRepositoryConfiguration fetches the repository configuration from Artifactory
182+
func getRepositoryConfiguration(repoKey string, serviceManager artifactory.ArtifactoryServicesManager) (*repositoryConfig, error) {
183+
// Create HTTP client details for the request
184+
httpClientDetails := serviceManager.GetConfig().GetServiceDetails().CreateHttpClientDetails()
185+
186+
// Construct the API endpoint URL
187+
baseUrl := serviceManager.GetConfig().GetServiceDetails().GetUrl()
188+
endpoint := "api/repositories/" + repoKey
189+
url := baseUrl + endpoint
190+
191+
// Make the HTTP GET request
192+
resp, body, _, err := serviceManager.Client().SendGet(url, true, &httpClientDetails)
193+
if err != nil {
194+
return nil, err
195+
}
196+
197+
// Check for successful response
198+
if resp.StatusCode != 200 {
199+
return nil, fmt.Errorf("failed to get repository configuration: HTTP %d", resp.StatusCode)
200+
}
201+
202+
// Parse the JSON response
203+
var config repositoryConfig
204+
if err := json.Unmarshal(body, &config); err != nil {
205+
return nil, fmt.Errorf("failed to parse repository configuration: %v", err)
206+
}
207+
208+
return &config, nil
209+
}
210+
122211
// Download the content of layer search result.
123212
func downloadLayer(searchResult utils.ResultItem, result interface{}, serviceManager artifactory.ArtifactoryServicesManager, repo string) error {
124213
// Search results may include artifacts from the remote-cache repository.
@@ -340,7 +429,7 @@ func (builder *buildInfoBuilder) createBuildInfo(commandType CommandType, manife
340429
return nil, err
341430
}
342431
if !builder.skipTaggingLayers {
343-
if err := setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager); err != nil {
432+
if err := setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager, builder.repositoryDetails.key); err != nil {
344433
return nil, err
345434
}
346435
}
@@ -399,7 +488,7 @@ func (builder *buildInfoBuilder) createMultiPlatformBuildInfo(fatManifest *FatMa
399488
Parent: imageLongNameWithoutRepo,
400489
})
401490
}
402-
return buildInfo, setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager)
491+
return buildInfo, setBuildProperties(builder.buildName, builder.buildNumber, builder.project, builder.imageLayers, builder.serviceManager, builder.repositoryDetails.key)
403492
}
404493

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

0 commit comments

Comments
 (0)