Skip to content

Commit

Permalink
Adds field labels-exclusion-pattern in feature-flag to exclude labels
Browse files Browse the repository at this point in the history
This adds a new field in feature-flag `labels-exclusion-pattern`
which by default is empty and takes regex pattern as input. If
defined this would filter out labels from propagating from el to
resources created for it such as deployment, service.

Signed-off-by: Shivam Mukhade <[email protected]>
  • Loading branch information
Shivam Mukhade authored and tekton-robot committed Sep 24, 2021
1 parent 5d6c86c commit 3b028b7
Show file tree
Hide file tree
Showing 18 changed files with 179 additions and 24 deletions.
3 changes: 3 additions & 0 deletions config/config-feature-flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ data:
# Setting this flag will determine which gated features are enabled.
# Acceptable values are "stable" or "alpha".
enable-api-fields: "stable"
# Setting this field with valid regex pattern matching the pattern will exclude labels from
# getting added to resources created by the EventListener such as the deployment
labels-exclusion-pattern: ""
6 changes: 6 additions & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ To customize the behavior of the Triggers Controller, modify the ConfigMap `feat
most stable features to be used. Set it to "alpha" to allow alpha
features (in addition to stable features) to be used. Note that this flag only applies to the v1beta1 apiVersion.

- `labels-exclusion-pattern`: set this field with regex pattern which will
exclude labels matching the pattern from getting added to resources created
by the EventListener such as the deployment. By default, there is no value is set
for this field so all labels added to the EventListener are propagated down.

For example:

```yaml
Expand All @@ -86,3 +91,4 @@ metadata:
name: feature-flags-triggers
data:
enable-api-fields: "alpha" # Allow "alpha" fields to be used in v1beta1 Triggers' resources. Defaults to "stable" features only.``
labels-exclusion-pattern: "^tekton-dev-"
26 changes: 26 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package config
import (
"fmt"
"os"
"regexp"
"strings"

corev1 "k8s.io/api/core/v1"
Expand All @@ -29,6 +30,8 @@ const (
AlphaAPIFieldValue = "alpha"
enableAPIFieldsKey = "enable-api-fields"
DefaultEnableAPIFields = StableAPIFieldValue

labelsExclusionPattern = "labels-exclusion-pattern"
)

// FeatureFlags holds the features configurations
Expand All @@ -37,6 +40,9 @@ type FeatureFlags struct {
// EnableAPIFields determines which gated features are enabled.
// Acceptable values are "stable" or "alpha". Defaults to "stable"
EnableAPIFields string
// LabelsExclusionPattern determines the regex pattern to use to exclude
// labels being propagated to resources created by the EventListener
LabelsExclusionPattern string
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand All @@ -55,9 +61,29 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if tc.EnableAPIFields, err = getEnabledAPI(cfgMap); err != nil {
return nil, err
}

if tc.LabelsExclusionPattern, err = getLabelsExclusionPattern(cfgMap); err != nil {
return nil, err
}

return &tc, nil
}

// getLabelsExclusionPattern gets the "labels-exclusion-pattern" flag based on the content of a given map.
// If the feature gate is not defined then we ignore it, if the pattern is not
// valid regex then we return error
func getLabelsExclusionPattern(cfgMap map[string]string) (string, error) {

if pattern, ok := cfgMap[labelsExclusionPattern]; ok {
if _, err := regexp.Compile(pattern); err != nil {
return "", fmt.Errorf("invalid value for feature flag %q: %q", labelsExclusionPattern, pattern)
}
return pattern, nil
}

return "", nil
}

// getEnabledAPI gets the "enable-api-fields" flag based on the content of a given map.
// If the feature gate is invalid or missing then an error is returned.
func getEnabledAPI(cfgMap map[string]string) (string, error) {
Expand Down
5 changes: 4 additions & 1 deletion pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
fileName: config.GetFeatureFlagsConfigName(),
}, {
expectedConfig: &config.FeatureFlags{
EnableAPIFields: "alpha",
EnableAPIFields: "alpha",
LabelsExclusionPattern: "^abc-",
},
fileName: "feature-flags-all-flags-set",
}, {
Expand Down Expand Up @@ -101,6 +102,8 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) {
fileName string
}{{
fileName: "feature-flags-invalid-enable-api-fields",
}, {
fileName: "feature-flags-invalid-exclusion-pattern-fields",
}} {
t.Run(tc.fileName, func(t *testing.T) {
cm := test.ConfigMapFromTestFile(t, tc.fileName)
Expand Down
10 changes: 8 additions & 2 deletions pkg/apis/config/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value i
"defaults/features/artifacts",
logger,
configmap.Constructors{
GetDefaultsConfigName(): NewDefaultsFromConfigMap,
GetFeatureFlagsConfigName(): NewFeatureFlagsFromConfigMap,
GetDefaultsConfigName(): NewDefaultsFromConfigMap,
},
onAfterStore...,
),
Expand All @@ -93,8 +94,13 @@ func (s *Store) Load() *Config {
if defaults == nil {
defaults, _ = NewDefaultsFromMap(map[string]string{})
}
featureFlags := s.UntypedLoad(GetFeatureFlagsConfigName())
if featureFlags == nil {
featureFlags, _ = NewFeatureFlagsFromMap(map[string]string{})
}

return &Config{
Defaults: defaults.(*Defaults).DeepCopy(),
Defaults: defaults.(*Defaults).DeepCopy(),
FeatureFlags: featureFlags.(*FeatureFlags).DeepCopy(),
}
}
5 changes: 4 additions & 1 deletion pkg/apis/config/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ func TestStoreLoadWithContext(t *testing.T) {

expectedDefaults, _ := config.NewDefaultsFromConfigMap(defaultConfig)

expectedFeatureFlag, _ := config.NewFeatureFlagsFromConfigMap(defaultConfig)

expected := &config.Config{
Defaults: expectedDefaults,
Defaults: expectedDefaults,
FeatureFlags: expectedFeatureFlag,
}

store := config.NewStore(logtesting.TestLogger(t))
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/config/testdata/feature-flags-all-flags-set.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ metadata:
namespace: tekton-pipelines
data:
enable-api-fields: "alpha"
labels-exclusion-pattern: "^abc-"
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2021 The Tekton 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
#
# https://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.

apiVersion: v1
kind: ConfigMap
metadata:
name: feature-flags-triggers
namespace: tekton-pipelines
data:
enable-api-fields: "stable"
labels-exclusion-pattern: "[0-9]++"
6 changes: 3 additions & 3 deletions pkg/reconciler/eventlistener/eventlistener.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, el *v1beta1.EventListene
}

func (r *Reconciler) reconcileService(ctx context.Context, el *v1beta1.EventListener) error {
service := resources.MakeService(el, r.config)
service := resources.MakeService(ctx, el, r.config)

existingService, err := r.serviceLister.Services(el.Namespace).Get(el.Status.Configuration.GeneratedResourceName)
switch {
Expand Down Expand Up @@ -178,7 +178,7 @@ func (r *Reconciler) reconcileService(ctx context.Context, el *v1beta1.EventList
}

func (r *Reconciler) reconcileDeployment(ctx context.Context, el *v1beta1.EventListener) error {
deployment, err := resources.MakeDeployment(el, r.configAcc, r.config)
deployment, err := resources.MakeDeployment(ctx, el, r.configAcc, r.config)
if err != nil {
logging.FromContext(ctx).Error(err)
return err
Expand Down Expand Up @@ -241,7 +241,7 @@ func (r *Reconciler) reconcileDeployment(ctx context.Context, el *v1beta1.EventL
}

func (r *Reconciler) reconcileCustomObject(ctx context.Context, el *v1beta1.EventListener) error {
data, err := resources.MakeCustomObject(el, r.configAcc, r.config)
data, err := resources.MakeCustomObject(ctx, el, r.configAcc, r.config)
if err != nil {
logging.FromContext(ctx).Errorf("unable to construct custom object", err)
return err
Expand Down
5 changes: 3 additions & 2 deletions pkg/reconciler/eventlistener/resources/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package resources

import (
"bytes"
"context"
"encoding/json"
"os"

Expand All @@ -30,7 +31,7 @@ import (
"knative.dev/pkg/kmeta"
)

func MakeCustomObject(el *v1beta1.EventListener, configAcc reconcilersource.ConfigAccessor, c Config) (*unstructured.Unstructured, error) {
func MakeCustomObject(ctx context.Context, el *v1beta1.EventListener, configAcc reconcilersource.ConfigAccessor, c Config) (*unstructured.Unstructured, error) {
original := &duckv1.WithPod{}
decoder := json.NewDecoder(bytes.NewBuffer(el.Spec.Resources.CustomResource.Raw))
if err := decoder.Decode(&original); err != nil {
Expand Down Expand Up @@ -77,7 +78,7 @@ func MakeCustomObject(el *v1beta1.EventListener, configAcc reconcilersource.Conf
}
})

podlabels := kmeta.UnionMaps(el.Labels, GenerateLabels(el.Name, c.StaticResourceLabels))
podlabels := kmeta.UnionMaps(FilterLabels(ctx, el.Labels), GenerateLabels(el.Name, c.StaticResourceLabels))

podlabels = kmeta.UnionMaps(podlabels, customObjectData.Labels)

Expand Down
5 changes: 3 additions & 2 deletions pkg/reconciler/eventlistener/resources/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package resources

import (
"context"
"os"
"strconv"
"testing"
Expand Down Expand Up @@ -296,7 +297,7 @@ func TestCustomObject(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := MakeCustomObject(tt.el, &reconcilersource.EmptyVarsGenerator{}, config)
got, err := MakeCustomObject(context.Background(), tt.el, &reconcilersource.EmptyVarsGenerator{}, config)
if err != nil {
t.Fatalf("MakeCustomObject() = %v", err)
}
Expand All @@ -319,7 +320,7 @@ func TestCustomObjectError(t *testing.T) {

config := *MakeConfig()

got, err := MakeCustomObject(makeEL(func(el *v1beta1.EventListener) {
got, err := MakeCustomObject(context.Background(), makeEL(func(el *v1beta1.EventListener) {
el.Spec.Resources.CustomResource = &v1beta1.CustomResource{
RawExtension: runtime.RawExtension{
Raw: []byte(`garbage`),
Expand Down
10 changes: 7 additions & 3 deletions pkg/reconciler/eventlistener/resources/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package resources

import (
"context"
"os"
"strconv"

Expand All @@ -40,16 +41,19 @@ var (
}
)

func MakeDeployment(el *v1beta1.EventListener, configAcc reconcilersource.ConfigAccessor, c Config) (*appsv1.Deployment, error) {
func MakeDeployment(ctx context.Context, el *v1beta1.EventListener, configAcc reconcilersource.ConfigAccessor, c Config) (*appsv1.Deployment, error) {

opt, err := addDeploymentBits(el, c)
if err != nil {
return nil, err
}

container := MakeContainer(el, configAcc, c, opt, addCertsForSecureConnection(c))

filteredLabels := FilterLabels(ctx, el.Labels)

var (
podlabels = kmeta.UnionMaps(el.Labels, GenerateLabels(el.Name, c.StaticResourceLabels))
podlabels = kmeta.UnionMaps(filteredLabels, GenerateLabels(el.Name, c.StaticResourceLabels))
serviceAccountName = el.Spec.ServiceAccountName
replicas *int32
vol []corev1.Volume
Expand Down Expand Up @@ -94,7 +98,7 @@ func MakeDeployment(el *v1beta1.EventListener, configAcc reconcilersource.Config
}

return &appsv1.Deployment{
ObjectMeta: ObjectMeta(el, c.StaticResourceLabels),
ObjectMeta: ObjectMeta(el, filteredLabels, c.StaticResourceLabels),
Spec: appsv1.DeploymentSpec{
Replicas: replicas,
Selector: &metav1.LabelSelector{
Expand Down
5 changes: 3 additions & 2 deletions pkg/reconciler/eventlistener/resources/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package resources

import (
"context"
"os"
"testing"

Expand Down Expand Up @@ -291,7 +292,7 @@ func TestDeployment(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := MakeDeployment(tt.el, &reconcilersource.EmptyVarsGenerator{}, config)
got, err := MakeDeployment(context.Background(), tt.el, &reconcilersource.EmptyVarsGenerator{}, config)
if err != nil {
t.Fatalf("MakeDeployment() = %v", err)
}
Expand All @@ -307,7 +308,7 @@ func TestDeploymentError(t *testing.T) {
if err != nil {
t.Fatal(err)
}
got, err := MakeDeployment(makeEL(), &reconcilersource.EmptyVarsGenerator{}, *MakeConfig())
got, err := MakeDeployment(context.Background(), makeEL(), &reconcilersource.EmptyVarsGenerator{}, *MakeConfig())
if err == nil {
t.Fatalf("MakeDeployment() = %v, wanted error", got)
}
Expand Down
29 changes: 27 additions & 2 deletions pkg/reconciler/eventlistener/resources/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ limitations under the License.
package resources

import (
"context"
"regexp"

"github.com/tektoncd/triggers/pkg/apis/config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/kmeta"

Expand All @@ -25,12 +29,12 @@ import (

// ObjectMeta generates the object meta that should be used by all
// resources generated by the EventListener reconciler
func ObjectMeta(el *v1beta1.EventListener, staticResourceLabels map[string]string) metav1.ObjectMeta {
func ObjectMeta(el *v1beta1.EventListener, filteredElLabels, staticResourceLabels map[string]string) metav1.ObjectMeta {
return metav1.ObjectMeta{
Namespace: el.Namespace,
Name: el.Status.Configuration.GeneratedResourceName,
OwnerReferences: []metav1.OwnerReference{*kmeta.NewControllerRef(el)},
Labels: kmeta.UnionMaps(el.Labels, GenerateLabels(el.Name, staticResourceLabels)),
Labels: kmeta.UnionMaps(filteredElLabels, GenerateLabels(el.Name, staticResourceLabels)),
Annotations: el.Annotations,
}
}
Expand All @@ -41,3 +45,24 @@ func GenerateLabels(eventListenerName string, staticResourceLabels map[string]st
resourceLabels["eventlistener"] = eventListenerName
return resourceLabels
}

// FilterLabels filters label based on regex pattern defined in
// feature-flag `labels-exclusion-pattern`
func FilterLabels(ctx context.Context, labels map[string]string) map[string]string {
cfg := config.FromContextOrDefaults(ctx)

if len(labels) == 0 || cfg.FeatureFlags.LabelsExclusionPattern == "" {
return labels
}

filteredLabels := make(map[string]string)
r := regexp.MustCompile(cfg.FeatureFlags.LabelsExclusionPattern)

for key, value := range labels {
if !r.MatchString(key) {
filteredLabels[key] = value
}
}

return filteredLabels
}
Loading

0 comments on commit 3b028b7

Please sign in to comment.