Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions pkg/storage/chunked.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ type chunk struct {
data []byte
}

type releaseWrapper struct {
release.Release
Labels map[string]string `json:"labels"`
}

func wrapRelease(rls *release.Release) *releaseWrapper {
return &releaseWrapper{
Release: *rls,
Labels: rls.Labels,
}
}

// encodeRelease encodes a release returning a base64 encoded
// gzipped string representation, or error.
func (c *chunkedSecrets) encodeReleaseAsChunks(key string, rls *release.Release) ([]chunk, error) {
Expand All @@ -105,7 +117,7 @@ func (c *chunkedSecrets) encodeReleaseAsChunks(key string, rls *release.Release)
return err
}
defer gzw.Close()
return json.NewEncoder(gzw).Encode(rls)
return json.NewEncoder(gzw).Encode(wrapRelease(rls))
}(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -318,29 +330,51 @@ func (c *chunkedSecrets) Query(queryLabels map[string]string) ([]*release.Releas
c.Log("query: labels=%v", queryLabels)
defer c.Log("queried: labels=%v", queryLabels)

selector := newListIndicesLabelSelector(c.owner)
if queryRequirements, selectable := labels.Set(queryLabels).AsSelector().Requirements(); selectable {
selector = selector.Add(queryRequirements...)
// The only labels that get stored on the index secret are system labels, so we'll do a two-pass
// query. First, we'll request index secrets from the API server that match the query labels that
// are system labels. From there, we decode the releases that match, and then further filter those
// based on the rest of the query labels that are not system labels.
Comment on lines +333 to +336
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was necessary to get existing tests to pass. We have a test that uses a custom label in a query.

serverSelectorSet := labels.Set{}
clientSelectorSet := labels.Set{}
for k, v := range queryLabels {
if isSystemLabel(k) {
serverSelectorSet[k] = v
} else {
clientSelectorSet[k] = v
}
}

indexSecrets, err := c.client.List(context.Background(), metav1.ListOptions{LabelSelector: selector.String()})
if err != nil {
return nil, fmt.Errorf("query: %w", err)
// Pass 1: build the server selector and query for index secrets
serverSelector := newListIndicesLabelSelector(c.owner)
if queryRequirements, selectable := serverSelectorSet.AsSelector().Requirements(); selectable {
serverSelector = serverSelector.Add(queryRequirements...)
}

if len(indexSecrets.Items) == 0 {
return nil, driver.ErrReleaseNotFound
indexSecrets, err := c.client.List(context.Background(), metav1.ListOptions{LabelSelector: serverSelector.String()})
if err != nil {
return nil, fmt.Errorf("query: %w", err)
}

// Pass 2: decode the releases that matched the server selector and filter based on the client selector
results := make([]*release.Release, 0, len(indexSecrets.Items))
clientSelector := clientSelectorSet.AsSelector()
for _, indexSecret := range indexSecrets.Items {
indexSecret := indexSecret
rls, err := c.decodeRelease(context.Background(), &indexSecret)
if err != nil {
return nil, fmt.Errorf("query: failed to decode release: %w", err)
}

if !clientSelector.Matches(labels.Set(rls.Labels)) {
continue
}
results = append(results, rls)
}

if len(results) == 0 {
return nil, driver.ErrReleaseNotFound
}

return results, nil
}

Expand Down Expand Up @@ -398,11 +432,13 @@ func (c *chunkedSecrets) decodeRelease(ctx context.Context, indexSecret *corev1.
return nil, fmt.Errorf("failed to create gzip reader: %w", err)
}
releaseDecoder := json.NewDecoder(gzr)
var r release.Release
if err := releaseDecoder.Decode(&r); err != nil {
var wrappedRelease releaseWrapper
if err := releaseDecoder.Decode(&wrappedRelease); err != nil {
return nil, fmt.Errorf("failed to decode release: %w", err)
}
r.Labels = filterSystemLabels(indexSecret.Labels)

r := wrappedRelease.Release
r.Labels = filterSystemLabels(wrappedRelease.Labels)
return &r, nil
}

Expand Down
2 changes: 0 additions & 2 deletions pkg/storage/labels.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package storage

import (
"maps"
"strconv"

"helm.sh/helm/v3/pkg/release"
Expand All @@ -11,7 +10,6 @@ import (

func newIndexLabels(owner, key string, rls *release.Release) map[string]string {
labels := map[string]string{}
maps.Copy(labels, rls.Labels)
labels["name"] = rls.Name
labels["owner"] = owner
labels["status"] = rls.Info.Status.String()
Expand Down