Skip to content

Commit c81bd89

Browse files
committedSep 12, 2024··
Revert "Improve helm dependency update performance"
The change in #11726 caused a regression where `helm dependency udpate` stopped working. The format of the internal representation of the data changed causing errors of "non-absolute URLs should be in form of repo_name/path_to_chart". See #13324 for more details. Since this change is in released Helm and it's a regression, reverting the original change was the fastest and safest route to deliver a fix as quickly as possible. Closes #13324 Signed-off-by: Matt Farina <matt.farina@suse.com>
1 parent 7d1df76 commit c81bd89

File tree

4 files changed

+26
-60
lines changed

4 files changed

+26
-60
lines changed
 

‎internal/resolver/resolver.go

+13-31
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,21 @@ func New(chartpath, cachepath string, registryClient *registry.Client) *Resolver
5252
}
5353

5454
// Resolve resolves dependencies and returns a lock file with the resolution.
55-
func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string) (*chart.Lock, map[string]string, error) {
55+
func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) {
5656

5757
// Now we clone the dependencies, locking as we go.
5858
locked := make([]*chart.Dependency, len(reqs))
5959
missing := []string{}
60-
loadedIndexFiles := make(map[string]*repo.IndexFile)
61-
urls := make(map[string]string)
6260
for i, d := range reqs {
6361
constraint, err := semver.NewConstraint(d.Version)
6462
if err != nil {
65-
return nil, nil, errors.Wrapf(err, "dependency %q has an invalid version/constraint format", d.Name)
63+
return nil, errors.Wrapf(err, "dependency %q has an invalid version/constraint format", d.Name)
6664
}
6765

6866
if d.Repository == "" {
6967
// Local chart subfolder
7068
if _, err := GetLocalPath(filepath.Join("charts", d.Name), r.chartpath); err != nil {
71-
return nil, nil, err
69+
return nil, err
7270
}
7371

7472
locked[i] = &chart.Dependency{
@@ -81,12 +79,12 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
8179
if strings.HasPrefix(d.Repository, "file://") {
8280
chartpath, err := GetLocalPath(d.Repository, r.chartpath)
8381
if err != nil {
84-
return nil, nil, err
82+
return nil, err
8583
}
8684

8785
ch, err := loader.LoadDir(chartpath)
8886
if err != nil {
89-
return nil, nil, err
87+
return nil, err
9088
}
9189

9290
v, err := semver.NewVersion(ch.Metadata.Version)
@@ -124,26 +122,14 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
124122
var ok bool
125123
found := true
126124
if !registry.IsOCI(d.Repository) {
127-
filepath := filepath.Join(r.cachepath, helmpath.CacheIndexFile(repoName))
128-
var repoIndex *repo.IndexFile
129-
130-
// Store previously loaded index files in a map. If repositories share the
131-
// same index file there is no need to reload the same file again. This
132-
// improves performance.
133-
if indexFile, loaded := loadedIndexFiles[filepath]; !loaded {
134-
var err error
135-
repoIndex, err = repo.LoadIndexFile(filepath)
136-
loadedIndexFiles[filepath] = repoIndex
137-
if err != nil {
138-
return nil, nil, errors.Wrapf(err, "no cached repository for %s found. (try 'helm repo update')", repoName)
139-
}
140-
} else {
141-
repoIndex = indexFile
125+
repoIndex, err := repo.LoadIndexFile(filepath.Join(r.cachepath, helmpath.CacheIndexFile(repoName)))
126+
if err != nil {
127+
return nil, errors.Wrapf(err, "no cached repository for %s found. (try 'helm repo update')", repoName)
142128
}
143129

144130
vs, ok = repoIndex.Entries[d.Name]
145131
if !ok {
146-
return nil, nil, errors.Errorf("%s chart not found in repo %s", d.Name, d.Repository)
132+
return nil, errors.Errorf("%s chart not found in repo %s", d.Name, d.Repository)
147133
}
148134
found = false
149135
} else {
@@ -165,7 +151,7 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
165151
ref := fmt.Sprintf("%s/%s", strings.TrimPrefix(d.Repository, fmt.Sprintf("%s://", registry.OCIScheme)), d.Name)
166152
tags, err := r.registryClient.Tags(ref)
167153
if err != nil {
168-
return nil, nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository)
154+
return nil, errors.Wrapf(err, "could not retrieve list of tags for repository %s", d.Repository)
169155
}
170156

171157
vs = make(repo.ChartVersions, len(tags))
@@ -186,7 +172,6 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
186172
Repository: d.Repository,
187173
Version: version,
188174
}
189-
190175
// The version are already sorted and hence the first one to satisfy the constraint is used
191176
for _, ver := range vs {
192177
v, err := semver.NewVersion(ver.Version)
@@ -197,9 +182,6 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
197182
}
198183
if constraint.Check(v) {
199184
found = true
200-
if len(ver.URLs) > 0 {
201-
urls[d.Repository+ver.Name+ver.Version] = ver.URLs[0]
202-
}
203185
locked[i].Version = v.Original()
204186
break
205187
}
@@ -210,19 +192,19 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string
210192
}
211193
}
212194
if len(missing) > 0 {
213-
return nil, nil, errors.Errorf("can't get a valid version for %d subchart(s): %s. Make sure a matching chart version exists in the repo, or change the version constraint in Chart.yaml", len(missing), strings.Join(missing, ", "))
195+
return nil, errors.Errorf("can't get a valid version for %d subchart(s): %s. Make sure a matching chart version exists in the repo, or change the version constraint in Chart.yaml", len(missing), strings.Join(missing, ", "))
214196
}
215197

216198
digest, err := HashReq(reqs, locked)
217199
if err != nil {
218-
return nil, nil, err
200+
return nil, err
219201
}
220202

221203
return &chart.Lock{
222204
Generated: time.Now(),
223205
Digest: digest,
224206
Dependencies: locked,
225-
}, urls, nil
207+
}, nil
226208
}
227209

228210
// HashReq generates a hash of the dependencies.

‎internal/resolver/resolver_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func TestResolve(t *testing.T) {
144144
r := New("testdata/chartpath", "testdata/repository", registryClient)
145145
for _, tt := range tests {
146146
t.Run(tt.name, func(t *testing.T) {
147-
l, _, err := r.Resolve(tt.req, repoNames)
147+
l, err := r.Resolve(tt.req, repoNames)
148148
if err != nil {
149149
if tt.err {
150150
return

‎pkg/downloader/manager.go

+8-24
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func (m *Manager) Build() error {
141141
}
142142

143143
// Now we need to fetch every package here into charts/
144-
return m.downloadAll(lock.Dependencies, nil)
144+
return m.downloadAll(lock.Dependencies)
145145
}
146146

147147
// Update updates a local charts directory.
@@ -191,13 +191,13 @@ func (m *Manager) Update() error {
191191

192192
// Now we need to find out which version of a chart best satisfies the
193193
// dependencies in the Chart.yaml
194-
lock, urls, err := m.resolve(req, repoNames)
194+
lock, err := m.resolve(req, repoNames)
195195
if err != nil {
196196
return err
197197
}
198198

199199
// Now we need to fetch every package here into charts/
200-
if err := m.downloadAll(lock.Dependencies, urls); err != nil {
200+
if err := m.downloadAll(lock.Dependencies); err != nil {
201201
return err
202202
}
203203

@@ -230,7 +230,7 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) {
230230
// resolve takes a list of dependencies and translates them into an exact version to download.
231231
//
232232
// This returns a lock file, which has all of the dependencies normalized to a specific version.
233-
func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, map[string]string, error) {
233+
func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) {
234234
res := resolver.New(m.ChartPath, m.RepositoryCache, m.RegistryClient)
235235
return res.Resolve(req, repoNames)
236236
}
@@ -239,7 +239,7 @@ func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string)
239239
//
240240
// It will delete versions of the chart that exist on disk and might cause
241241
// a conflict.
242-
func (m *Manager) downloadAll(deps []*chart.Dependency, urls map[string]string) error {
242+
func (m *Manager) downloadAll(deps []*chart.Dependency) error {
243243
repos, err := m.loadChartRepositories()
244244
if err != nil {
245245
return err
@@ -312,7 +312,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency, urls map[string]string)
312312

313313
// Any failure to resolve/download a chart should fail:
314314
// https://github.com/helm/helm/issues/1439
315-
churl, username, password, insecureskiptlsverify, passcredentialsall, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos, urls)
315+
churl, username, password, insecureskiptlsverify, passcredentialsall, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
316316
if err != nil {
317317
saveError = errors.Wrapf(err, "could not find %s", churl)
318318
break
@@ -501,7 +501,6 @@ func (m *Manager) ensureMissingRepos(repoNames map[string]string, deps []*chart.
501501

502502
var ru []*repo.Entry
503503

504-
Outer:
505504
for _, dd := range deps {
506505

507506
// If the chart is in the local charts directory no repository needs
@@ -529,14 +528,6 @@ Outer:
529528

530529
repoNames[dd.Name] = rn
531530

532-
// If repository is already present don't add to array. This will skip
533-
// unnecessary index file downloading improving performance.
534-
for _, item := range ru {
535-
if item.URL == dd.Repository {
536-
continue Outer
537-
}
538-
}
539-
540531
// Assuming the repository is generally available. For Helm managed
541532
// access controls the repository needs to be added through the user
542533
// managed system. This path will work for public charts, like those
@@ -712,7 +703,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
712703
// repoURL is the repository to search
713704
//
714705
// If it finds a URL that is "relative", it will prepend the repoURL.
715-
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository, urls map[string]string) (url, username, password string, insecureskiptlsverify, passcredentialsall bool, caFile, certFile, keyFile string, err error) {
706+
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, insecureskiptlsverify, passcredentialsall bool, caFile, certFile, keyFile string, err error) {
716707
if registry.IsOCI(repoURL) {
717708
return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, false, "", "", "", nil
718709
}
@@ -751,14 +742,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
751742
return
752743
}
753744
}
754-
755-
urlsKey := repoURL + name + version
756-
if _, ok := urls[urlsKey]; ok {
757-
url = urls[urlsKey]
758-
} else {
759-
url, err = repo.FindChartInRepoURL(repoURL, name, version, certFile, keyFile, caFile, m.Getters)
760-
}
761-
745+
url, err = repo.FindChartInRepoURL(repoURL, name, version, certFile, keyFile, caFile, m.Getters)
762746
if err == nil {
763747
return url, username, password, false, false, "", "", "", err
764748
}

‎pkg/downloader/manager_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func TestFindChartURL(t *testing.T) {
8484
version := "0.1.0"
8585
repoURL := "http://example.com/charts"
8686

87-
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos, make(map[string]string))
87+
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos)
8888
if err != nil {
8989
t.Fatal(err)
9090
}
@@ -109,7 +109,7 @@ func TestFindChartURL(t *testing.T) {
109109
version = "1.2.3"
110110
repoURL = "https://example-https-insecureskiptlsverify.com"
111111

112-
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos, make(map[string]string))
112+
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
113113
if err != nil {
114114
t.Fatal(err)
115115
}
@@ -255,7 +255,7 @@ func TestDownloadAll(t *testing.T) {
255255
if err := os.MkdirAll(filepath.Join(chartPath, "tmpcharts"), 0755); err != nil {
256256
t.Fatal(err)
257257
}
258-
if err := m.downloadAll([]*chart.Dependency{signDep, localDep}, make(map[string]string)); err != nil {
258+
if err := m.downloadAll([]*chart.Dependency{signDep, localDep}); err != nil {
259259
t.Error(err)
260260
}
261261

@@ -284,7 +284,7 @@ version: 0.1.0`
284284
Version: "0.1.0",
285285
}
286286

287-
err = m.downloadAll([]*chart.Dependency{badLocalDep}, make(map[string]string))
287+
err = m.downloadAll([]*chart.Dependency{badLocalDep})
288288
if err == nil {
289289
t.Fatal("Expected error for bad dependency name")
290290
}

0 commit comments

Comments
 (0)
Please sign in to comment.