Skip to content

Commit

Permalink
predicate for helm (#4997)
Browse files Browse the repository at this point in the history
Signed-off-by: Venkat Ramaraju <venky2063@gmail.com>
  • Loading branch information
VenkatRamaraju committed Aug 2, 2021
1 parent 6351af5 commit 65480f4
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 5 deletions.
7 changes: 7 additions & 0 deletions changelog/fragments/helm-labelselector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
entries:
- description: >
Added a predicate for helm operators that filters resources based on selectors specified in watches.yaml.
Only the resources that contain the labels specified by selectors will be reconciled.
kind: addition
breaking: false
1 change: 1 addition & 0 deletions internal/cmd/helm-operator/run/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func run(cmd *cobra.Command, f *flags.Flags) {
WatchDependentResources: *w.WatchDependentResources,
OverrideValues: w.OverrideValues,
MaxConcurrentReconciles: f.MaxConcurrentReconciles,
Selector: w.Selector,
})
if err != nil {
log.Error(err, "Failed to add manager factory to controller.")
Expand Down
31 changes: 30 additions & 1 deletion internal/helm/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package controller

import (
"fmt"
"reflect"
"strings"
"sync"
"time"
Expand All @@ -30,6 +31,7 @@ import (
crthandler "sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
ctrlpredicate "sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/source"
"sigs.k8s.io/yaml"

Expand All @@ -51,6 +53,7 @@ type WatchOptions struct {
WatchDependentResources bool
OverrideValues map[string]string
MaxConcurrentReconciles int
Selector metav1.LabelSelector
}

// Add creates a new helm operator controller and adds it to the manager
Expand Down Expand Up @@ -80,7 +83,19 @@ func Add(mgr manager.Manager, options WatchOptions) error {

o := &unstructured.Unstructured{}
o.SetGroupVersionKind(options.GVK)
if err := c.Watch(&source.Kind{Type: o}, &libhandler.InstrumentedEnqueueRequestForObject{}); err != nil {

var preds []ctrlpredicate.Predicate
p, err := parsePredicateSelector(options.Selector)

if err != nil {
return err
}

if p != nil {
preds = append(preds, p)
}

if err := c.Watch(&source.Kind{Type: o}, &libhandler.InstrumentedEnqueueRequestForObject{}, preds...); err != nil {
return err
}

Expand All @@ -93,6 +108,20 @@ func Add(mgr manager.Manager, options WatchOptions) error {
return nil
}

// parsePredicateSelector parses the selector in the WatchOptions and creates a predicate
// that is used to filter resources based on the specified selector
func parsePredicateSelector(selector metav1.LabelSelector) (ctrlpredicate.Predicate, error) {
// If a selector has been specified in watches.yaml, add it to the watch's predicates.
if !reflect.ValueOf(selector).IsZero() {
p, err := ctrlpredicate.LabelSelectorPredicate(selector)
if err != nil {
return nil, fmt.Errorf("error constructing predicate from watches selector: %v", err)
}
return p, nil
}
return nil, nil
}

// watchDependentResources adds a release hook function to the HelmOperatorReconciler
// that adds watches for resources in released Helm charts.
func watchDependentResources(mgr manager.Manager, r *HelmOperatorReconciler, c controller.Controller) {
Expand Down
39 changes: 39 additions & 0 deletions internal/helm/controller/controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2021 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package controller

import (
"testing"

"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestFilterPredicate(t *testing.T) {
matchLabelPass := make(map[string]string)
matchLabelPass["testKey"] = "testValue"
selectorPass := metav1.LabelSelector{
MatchLabels: matchLabelPass,
}
noSelector := metav1.LabelSelector{}

passPredicate, err := parsePredicateSelector(selectorPass)
assert.Equal(t, nil, err, "Verify that no error is thrown on a valid populated selector")
assert.NotEqual(t, nil, passPredicate, "Verify that a predicate is constructed using a valid selector")

nilPredicate, err := parsePredicateSelector(noSelector)
assert.Equal(t, nil, err, "Verify that no error is thrown on a valid unpopulated selector")
assert.Equal(t, nil, nilPredicate, "Verify correct parsing of an unpopulated selector")
}
8 changes: 5 additions & 3 deletions internal/helm/watches/watches.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"

"helm.sh/helm/v3/pkg/chartutil"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/yaml"
)
Expand All @@ -32,9 +33,10 @@ const WatchesFile = "watches.yaml"
// custom resource.
type Watch struct {
schema.GroupVersionKind `json:",inline"`
ChartDir string `json:"chart"`
WatchDependentResources *bool `json:"watchDependentResources,omitempty"`
OverrideValues map[string]string `json:"overrideValues,omitempty"`
ChartDir string `json:"chart"`
WatchDependentResources *bool `json:"watchDependentResources,omitempty"`
OverrideValues map[string]string `json:"overrideValues,omitempty"`
Selector metav1.LabelSelector `json:"selector"`
}

// UnmarshalYAML unmarshals an individual watch from the Helm watches.yaml file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The follow tables describes the fields in an entry in `watches.yaml`:
| chart | The path to the helm chart to use when reconciling this GVK. |
| watchDependentResources | Enable watching resources that are created by helm (default: `true`). |
| overrideValues | Values to be used for overriding Helm chart's defaults. For additional information see the [reference doc][override-values]. |
| selector | The conditions that a resource's labels must satsify in order to get reconciled. For additional information see [labels and selectors documentation][label-selector-doc]. |


For reference, here is an example of a simple `watches.yaml` file:
Expand All @@ -31,7 +32,11 @@ For reference, here is an example of a simple `watches.yaml` file:
chart: helm-charts/foo
overrideValues:
image.repository: quay.io/mycustomrepo
watchDependentResources: false
watchDependentResources: false
selector:
matchExpressions:
- {key: testLabel, operator: Exists, values: []}
```

[override-values]: /docs/building-operators/helm/reference/advanced_features/override_values/
[label-selector-doc]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/

0 comments on commit 65480f4

Please sign in to comment.