1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-19 05:19:39 +02:00

feat(helm): filter on chart versions at API level [R8S-324] (#747)

This commit is contained in:
Cara Ryan 2025-05-26 14:10:38 +12:00 committed by GitHub
parent b96328e098
commit a80b185e10
6 changed files with 153 additions and 51 deletions

View file

@ -4,6 +4,8 @@ import (
"net/url"
"os"
"path/filepath"
"sync"
"time"
"github.com/pkg/errors"
"github.com/portainer/portainer/pkg/libhelm/options"
@ -25,6 +27,17 @@ type RepoIndex struct {
Generated string `json:"generated"`
}
type RepoIndexCache struct {
Index *repo.IndexFile
Timestamp time.Time
}
var (
indexCache = make(map[string]RepoIndexCache)
cacheMutex sync.RWMutex
cacheDuration = 60 * time.Minute
)
// SearchRepo downloads the `index.yaml` file for specified repo, parses it and returns JSON to caller.
func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoOptions) ([]byte, error) {
// Validate input options
@ -53,6 +66,18 @@ func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoO
return nil, err
}
// Check cache first
if searchRepoOpts.UseCache {
cacheMutex.RLock()
if cached, exists := indexCache[repoURL.String()]; exists {
if time.Since(cached.Timestamp) < cacheDuration {
cacheMutex.RUnlock()
return convertAndMarshalIndex(cached.Index, searchRepoOpts.Chart)
}
}
cacheMutex.RUnlock()
}
// Set up Helm CLI environment
repoSettings := cli.New()
@ -92,23 +117,21 @@ func (hspm *HelmSDKPackageManager) SearchRepo(searchRepoOpts options.SearchRepoO
return nil, err
}
// Convert the index file to our response format
result, err := convertIndexToResponse(indexFile)
if err != nil {
log.Error().
Str("context", "HelmClient").
Err(err).
Msg("Failed to convert index to response format")
return nil, errors.Wrap(err, "failed to convert index to response format")
// Update cache and remove old entries
cacheMutex.Lock()
indexCache[searchRepoOpts.Repo] = RepoIndexCache{
Index: indexFile,
Timestamp: time.Now(),
}
for key, index := range indexCache {
if time.Since(index.Timestamp) > cacheDuration {
delete(indexCache, key)
}
}
log.Debug().
Str("context", "HelmClient").
Str("repo", searchRepoOpts.Repo).
Int("entries_count", len(indexFile.Entries)).
Msg("Successfully searched repository")
cacheMutex.Unlock()
return json.Marshal(result)
return convertAndMarshalIndex(indexFile, searchRepoOpts.Chart)
}
// validateSearchRepoOptions validates the required search repository options.
@ -216,7 +239,7 @@ func loadIndexFile(indexPath string) (*repo.IndexFile, error) {
}
// convertIndexToResponse converts the Helm index file to our response format.
func convertIndexToResponse(indexFile *repo.IndexFile) (RepoIndex, error) {
func convertIndexToResponse(indexFile *repo.IndexFile, chartName string) (RepoIndex, error) {
result := RepoIndex{
APIVersion: indexFile.APIVersion,
Entries: make(map[string][]ChartInfo),
@ -225,7 +248,9 @@ func convertIndexToResponse(indexFile *repo.IndexFile) (RepoIndex, error) {
// Convert Helm SDK types to our response types
for name, charts := range indexFile.Entries {
result.Entries[name] = convertChartsToChartInfo(charts)
if chartName == "" || name == chartName {
result.Entries[name] = convertChartsToChartInfo(charts)
}
}
return result, nil
@ -349,3 +374,23 @@ func ensureHelmDirectoriesExist(settings *cli.EnvSettings) error {
return nil
}
func convertAndMarshalIndex(indexFile *repo.IndexFile, chartName string) ([]byte, error) {
// Convert the index file to our response format
result, err := convertIndexToResponse(indexFile, chartName)
if err != nil {
log.Error().
Str("context", "HelmClient").
Err(err).
Msg("Failed to convert index to response format")
return nil, errors.Wrap(err, "failed to convert index to response format")
}
log.Debug().
Str("context", "HelmClient").
Str("repo", chartName).
Int("entries_count", len(indexFile.Entries)).
Msg("Successfully searched repository")
return json.Marshal(result)
}