fix(downloader): serialize downloadAll per ChartPath

safeMoveDeps reads the destination charts/ directory and then moves
in new charts and deletes ones missing from that snapshot. Separate
Manager instances calling downloadAll concurrently against the same
ChartPath can race on this read-then-write, e.g. one call's freshly
moved-in chart being deleted by another call's "delete outdated
charts" pass because it wasn't in that call's earlier snapshot.

Signed-off-by: Anis Khan <2815766+aniskhan001@users.noreply.github.com>
pull/32533/head
Anis Khan 1 month ago
parent 7a0bf95a5e
commit 280cdc4f0c
No known key found for this signature in database
GPG Key ID: 1E7BFF978E3EEBB3

@ -240,11 +240,26 @@ func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string)
return res.Resolve(req, repoNames)
}
// chartPathLocks serializes downloadAll calls per ChartPath, since concurrent
// calls targeting the same path can race on the shared "charts/" directory.
var chartPathLocks sync.Map // map[string]*sync.Mutex
func lockForChartPath(chartPath string) *sync.Mutex {
lock, _ := chartPathLocks.LoadOrStore(chartPath, &sync.Mutex{})
return lock.(*sync.Mutex)
}
// downloadAll takes a list of dependencies and downloads them into charts/
//
// It will delete versions of the chart that exist on disk and might cause
// a conflict.
func (m *Manager) downloadAll(deps []*chart.Dependency) error {
// safeMoveDeps below isn't safe against other calls targeting the same
// ChartPath, so serialize per-path here.
lock := lockForChartPath(m.ChartPath)
lock.Lock()
defer lock.Unlock()
repos, err := m.loadChartRepositories()
if err != nil {
return err

Loading…
Cancel
Save