diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 85f3497e7..831089638 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -38,8 +38,14 @@ import ( var _ Driver = (*Secrets)(nil) -// SecretsDriverName is the string name of the driver. -const SecretsDriverName = "Secret" +const ( + // SecretsDriverName is the string name of the driver. + SecretsDriverName = "Secret" + // owner is owner of the secret + owner = "helm" + // DefaultPaginationLimit . + DefaultPaginationLimit = 50 +) // Secrets is a wrapper around an implementation of a kubernetes // SecretsInterface. @@ -84,11 +90,52 @@ func (secrets *Secrets) Get(key string) (release.Releaser, error) { return r, nil } +// listPages common methods to list release pagination +func (secrets *Secrets) listPages(f func(page []release.Releaser, lastPage bool) (end bool), opts metav1.ListOptions, filter func(release.Releaser) bool) (err error) { + token := "" + if opts.Limit == 0 { + opts.Limit = DefaultPaginationLimit + } + +Loop: + for { + list, err := secrets.impl.List(context.Background(), opts) + if nil != err { + return err + } + token = list.Continue + + var results []release.Releaser + + // iterate over the secrets object list + // and decode each release + for _, item := range list.Items { + rls, err := decodeRelease(string(item.Data["release"])) + if err != nil { + secrets.Logger().Debug("list failed to decode release", "key", item.Name, slog.Any("error", err)) + continue + } + + rls.Labels = item.Labels + + if filter(rls) { + results = append(results, rls) + } + } + + if f(results, token != "") { + break Loop + } + } + + return nil +} + // List fetches all releases and returns the list releases such // that filter(release) == true. An error is returned if the // secret fails to retrieve the releases. func (secrets *Secrets) List(filter func(release.Releaser) bool) ([]release.Releaser, error) { - lsel := kblabels.Set{"owner": "helm"}.AsSelector() + lsel := kblabels.Set{"owner": owner}.AsSelector() opts := metav1.ListOptions{LabelSelector: lsel.String()} list, err := secrets.impl.List(context.Background(), opts) @@ -116,6 +163,14 @@ func (secrets *Secrets) List(filter func(release.Releaser) bool) ([]release.Rele return results, nil } +// ListPages same as List, but with pagination +func (secrets *Secrets) ListPages(f func(page []release.Releaser, lastPage bool) (end bool), filter func(release.Releaser) bool) error { + lsel := kblabels.Set{"owner": owner}.AsSelector() + opts := metav1.ListOptions{LabelSelector: lsel.String()} + + return secrets.listPages(f, opts, filter) +} + // Query fetches all releases that match the provided map of labels. // An error is returned if the secret fails to retrieve the releases. func (secrets *Secrets) Query(labels map[string]string) ([]release.Releaser, error) { @@ -151,6 +206,21 @@ func (secrets *Secrets) Query(labels map[string]string) ([]release.Releaser, err return results, nil } +// QueryPages same as Query, but with pagination +func (secrets *Secrets) QueryPages(f func(page []release.Releaser, lastPage bool) (end bool), labels map[string]string) error { + ls := kblabels.Set{} + for k, v := range labels { + if errs := validation.IsValidLabelValue(v); len(errs) != 0 { + return fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; ")) + } + ls[k] = v + } + + opts := metav1.ListOptions{LabelSelector: ls.AsSelector().String()} + + return secrets.listPages(f, opts, func(release.Releaser) bool { return true }) +} + // Create creates a new Secret holding the release. If the // Secret already exists, ErrReleaseExists is returned. func (secrets *Secrets) Create(key string, rel release.Releaser) error { @@ -237,8 +307,6 @@ func (secrets *Secrets) Delete(key string) (rls release.Releaser, err error) { // "owner" - owner of the secret, currently "helm". // "name" - name of the release. func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, error) { - const owner = "helm" - // encode the release s, err := encodeRelease(rls) if err != nil {