From 565c55b30e422fc7fca42bc122561aa231106204 Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 29 Apr 2021 15:56:39 -0400 Subject: [PATCH] Enable Bundles and Custom Tasks when alpha feature gate is set to "alpha" Prior to this commit the Tekton Bundles and Custom Task features were only enabled when their individual flags were set to "true" in the feature-flags configmap. After this commit the two features are enabled if enable-api-fields is "alpha" or if their individual flags are set to "true". Note that it is _not_ possible to set the "alpha" feature gate but disable Bundles / Custom Tasks. These features are "alpha features" so they're always enabled regardless of their own feature flags if the gate is set to "alpha". --- docs/developers/README.md | 4 ++-- docs/install.md | 11 +++++++++ docs/taskruns.md | 3 ++- .../taskruns/workspace-in-sidecar.yaml | 8 +++++++ pkg/apis/config/feature_flags.go | 24 ++++++++++++++----- pkg/apis/config/feature_flags_test.go | 22 +++++++++++++++++ ...eature-flags-bundles-and-custom-tasks.yaml | 9 +++++++ ...ds-overrides-bundles-and-custom-tasks.yaml | 9 +++++++ test/custom_task_test.go | 7 +++++- test/gate.go | 23 +++++++++++------- test/tektonbundles_test.go | 11 ++++++--- 11 files changed, 110 insertions(+), 21 deletions(-) create mode 100644 pkg/apis/config/testdata/feature-flags-bundles-and-custom-tasks.yaml create mode 100644 pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml diff --git a/docs/developers/README.md b/docs/developers/README.md index c9dc051af5f..6ee45047ae7 100644 --- a/docs/developers/README.md +++ b/docs/developers/README.md @@ -451,11 +451,11 @@ backwards-compatibility of the examples under alpha conditions. ### Integration Tests -For integration tests we provide the [`requireGate` function](../../test/gate.go) which +For integration tests we provide the [`requireAnyGate` function](../../test/gate.go) which should be passed to the `setup` function used by tests: ```go -c, namespace := setup(ctx, t, requireGate("enable-api-fields", "alpha")) +c, namespace := setup(ctx, t, requireAnyGate(map[string]string{"enable-api-fields": "alpha"})) ``` This will Skip your integration test if the feature gate is not set to `alpha` diff --git a/docs/install.md b/docs/install.md index 15526d9e83d..fe2dda9900c 100644 --- a/docs/install.md +++ b/docs/install.md @@ -374,6 +374,17 @@ data: enable-api-fields: "alpha" # Allow alpha fields to be used in Tasks and Pipelines. ``` +### Alpha Features + +Alpha features are still in development and their syntax is subject to change. +To enable these, set the `enable-api-fields` feature flag to `"alpha"` in +the `feature-flags` ConfigMap alongside your Tekton Pipelines deployment. + +Features currently in "alpha" are: + +- [Tekton Bundles](./taskruns.md#tekton-bundles) +- [Custom Tasks](./runs.md) + ## Configuring High Availability If you want to run Tekton Pipelines in a way so that webhooks are resiliant against failures and support diff --git a/docs/taskruns.md b/docs/taskruns.md index f68573bebc2..645d5032285 100644 --- a/docs/taskruns.md +++ b/docs/taskruns.md @@ -100,7 +100,8 @@ spec: ### Tekton Bundles **Note: This is only allowed if `enable-tekton-oci-bundles` is set to -`"true"` in the `feature-flags` configmap, see [`install.md`](./install.md#customizing-the-pipelines-controller-behavior)** +`"true"` or `enable-api-fields` is set to `"alpha"` in the `feature-flags` +configmap, see [`install.md`](./install.md#customizing-the-pipelines-controller-behavior)** You may also reference `Tasks` that are defined outside of your cluster using `Tekton Bundles`. A `Tekton Bundle` is an OCI artifact that contains Tekton resources like `Tasks` diff --git a/examples/v1beta1/taskruns/workspace-in-sidecar.yaml b/examples/v1beta1/taskruns/workspace-in-sidecar.yaml index 3c758107bd6..44c8283cdec 100644 --- a/examples/v1beta1/taskruns/workspace-in-sidecar.yaml +++ b/examples/v1beta1/taskruns/workspace-in-sidecar.yaml @@ -19,6 +19,10 @@ spec: - name: signals steps: - image: alpine:3.12.0 + resources: + requests: + memory: "64Mi" + cpu: "250m" script: | #!/usr/bin/env ash echo "foo" > "$(workspaces.signals.path)"/bar @@ -30,6 +34,10 @@ spec: echo "Saw ready file" sidecars: - image: alpine:3.12.0 + resources: + requests: + memory: "64Mi" + cpu: "250m" # Note: must explicitly add volumeMount to gain access to Workspace in sidecar volumeMounts: - name: $(workspaces.signals.volume) diff --git a/pkg/apis/config/feature_flags.go b/pkg/apis/config/feature_flags.go index e6f83c053fe..a60a2f0d623 100644 --- a/pkg/apis/config/feature_flags.go +++ b/pkg/apis/config/feature_flags.go @@ -105,15 +105,27 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) { if err := setFeature(requireGitSSHSecretKnownHostsKey, DefaultRequireGitSSHSecretKnownHosts, &tc.RequireGitSSHSecretKnownHosts); err != nil { return nil, err } - if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil { - return nil, err - } - if err := setFeature(enableCustomTasks, DefaultEnableCustomTasks, &tc.EnableCustomTasks); err != nil { - return nil, err - } if err := setEnabledAPIFields(cfgMap, DefaultEnableAPIFields, &tc.EnableAPIFields); err != nil { return nil, err } + + // Given that they are alpha features, Tekton Bundles and Custom Tasks should be switched on if + // enable-api-fields is "alpha". If enable-api-fields is not "alpha" then fall back to the value of + // each feature's individual flag. + // + // Note: the user cannot enable "alpha" while disabling bundles or custom tasks - that would + // defeat the purpose of having a single shared gate for all alpha features. + if tc.EnableAPIFields == AlphaAPIFields { + tc.EnableTektonOCIBundles = true + tc.EnableCustomTasks = true + } else { + if err := setFeature(enableTektonOCIBundles, DefaultEnableTektonOciBundles, &tc.EnableTektonOCIBundles); err != nil { + return nil, err + } + if err := setFeature(enableCustomTasks, DefaultEnableCustomTasks, &tc.EnableCustomTasks); err != nil { + return nil, err + } + } return &tc, nil } diff --git a/pkg/apis/config/feature_flags_test.go b/pkg/apis/config/feature_flags_test.go index 53c93bef479..f2b288a0ff0 100644 --- a/pkg/apis/config/feature_flags_test.go +++ b/pkg/apis/config/feature_flags_test.go @@ -53,6 +53,28 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) { }, fileName: "feature-flags-all-flags-set", }, + { + expectedConfig: &config.FeatureFlags{ + EnableAPIFields: "alpha", + // These are prescribed as true by enabling "alpha" API fields, even + // if the submitted text value is "false". + EnableTektonOCIBundles: true, + EnableCustomTasks: true, + + RunningInEnvWithInjectedSidecars: config.DefaultRunningInEnvWithInjectedSidecars, + }, + fileName: "feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks", + }, + { + expectedConfig: &config.FeatureFlags{ + EnableAPIFields: "stable", + EnableTektonOCIBundles: true, + EnableCustomTasks: true, + + RunningInEnvWithInjectedSidecars: config.DefaultRunningInEnvWithInjectedSidecars, + }, + fileName: "feature-flags-bundles-and-custom-tasks", + }, } for _, tc := range testCases { diff --git a/pkg/apis/config/testdata/feature-flags-bundles-and-custom-tasks.yaml b/pkg/apis/config/testdata/feature-flags-bundles-and-custom-tasks.yaml new file mode 100644 index 00000000000..9ea07b098bf --- /dev/null +++ b/pkg/apis/config/testdata/feature-flags-bundles-and-custom-tasks.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: feature-flags + namespace: tekton-pipelines +data: + enable-tekton-oci-bundles: "true" + enable-custom-tasks: "true" + enable-api-fields: "stable" diff --git a/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml b/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml new file mode 100644 index 00000000000..545ba7fe21d --- /dev/null +++ b/pkg/apis/config/testdata/feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: feature-flags + namespace: tekton-pipelines +data: + enable-tekton-oci-bundles: "false" + enable-custom-tasks: "false" + enable-api-fields: "alpha" diff --git a/test/custom_task_test.go b/test/custom_task_test.go index 3e4e8a93954..ac76f818b86 100644 --- a/test/custom_task_test.go +++ b/test/custom_task_test.go @@ -39,11 +39,16 @@ const ( kind = "Example" ) +var supportedFeatureGates = map[string]string{ + "enable-custom-tasks": "true", + "enable-api-fields": "alpha", +} + func TestCustomTask(t *testing.T) { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() - c, namespace := setup(ctx, t, requireGate("enable-custom-tasks", "true")) + c, namespace := setup(ctx, t, requireAnyGate(supportedFeatureGates)) knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf) defer tearDown(ctx, t, c, namespace) diff --git a/test/gate.go b/test/gate.go index 580a621b24a..13292e1c411 100644 --- a/test/gate.go +++ b/test/gate.go @@ -2,6 +2,8 @@ package test import ( "context" + "fmt" + "strings" "testing" "github.com/tektoncd/pipeline/pkg/apis/config" @@ -9,19 +11,24 @@ import ( "knative.dev/pkg/system" ) -// requireGate returns a setup func that will skip the current -// test if the feature-flag with given name does not equal -// given value. It will fatally fail the test if it cannot get -// the feature-flag configmap. -func requireGate(name, value string) func(context.Context, *testing.T, *clients, string) { +// requireAnyGate returns a setup func that will skip the current +// test if none of the feature-flags in the given map match +// what's in the feature-flags ConfigMap. It will fatally fail +// the test if it cannot get the feature-flag configmap. +func requireAnyGate(gates map[string]string) func(context.Context, *testing.T, *clients, string) { return func(ctx context.Context, t *testing.T, c *clients, namespace string) { featureFlagsCM, err := c.KubeClient.CoreV1().ConfigMaps(system.Namespace()).Get(ctx, config.GetFeatureFlagsConfigName(), metav1.GetOptions{}) if err != nil { t.Fatalf("Failed to get ConfigMap `%s`: %s", config.GetFeatureFlagsConfigName(), err) } - val, ok := featureFlagsCM.Data[name] - if !ok || val != value { - t.Skipf("Skipped because feature gate %q != %q", name, value) + pairs := []string{} + for name, value := range gates { + actual, ok := featureFlagsCM.Data[name] + if ok && value == actual { + return + } + pairs = append(pairs, fmt.Sprintf("%q: %q", name, value)) } + t.Skipf("No feature flag matching %s", strings.Join(pairs, " or ")) } } diff --git a/test/tektonbundles_test.go b/test/tektonbundles_test.go index e689a99eb1d..a6d7c1364e7 100644 --- a/test/tektonbundles_test.go +++ b/test/tektonbundles_test.go @@ -45,11 +45,16 @@ import ( knativetest "knative.dev/pkg/test" ) +var requireFeatureFlags = requireAnyGate(map[string]string{ + "enable-tekton-oci-bundles": "true", + "enable-api-fields": "alpha", +}) + // TestTektonBundlesSimpleWorkingExample is an integration test which tests a simple, working Tekton bundle using OCI // images. func TestTektonBundlesSimpleWorkingExample(t *testing.T) { ctx := context.Background() - c, namespace := setup(ctx, t, withRegistry, requireGate("enable-tekton-oci-bundles", "true")) + c, namespace := setup(ctx, t, withRegistry, requireFeatureFlags) t.Parallel() @@ -189,7 +194,7 @@ func TestTektonBundlesSimpleWorkingExample(t *testing.T) { // TestTektonBundlesUsingRegularImage is an integration test which passes a non-Tekton bundle as a task reference. func TestTektonBundlesUsingRegularImage(t *testing.T) { ctx := context.Background() - c, namespace := setup(ctx, t, withRegistry, requireGate("enable-tekton-oci-bundles", "true")) + c, namespace := setup(ctx, t, withRegistry, requireFeatureFlags) t.Parallel() @@ -274,7 +279,7 @@ func TestTektonBundlesUsingRegularImage(t *testing.T) { // task reference. func TestTektonBundlesUsingImproperFormat(t *testing.T) { ctx := context.Background() - c, namespace := setup(ctx, t, withRegistry, requireGate("enable-tekton-oci-bundles", "true")) + c, namespace := setup(ctx, t, withRegistry, requireFeatureFlags) t.Parallel()