Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TEP-0135: Introduce coschedule feature flags #6790

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
12 changes: 12 additions & 0 deletions config/config-feature-flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ data:
# https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#affinity-assistant-and-specifying-workspace-order-in-a-pipeline
# or https://github.com/tektoncd/pipeline/pull/2630 for more info.
disable-affinity-assistant: "false"
# Setting this flag will determine how PipelineRun Pods are scheduled with Affinity Assistant.
# Acceptable values are "workspaces" (default), "pipelineruns", "isolate-pipelinerun", or "disabled".
#
# Setting it to "workspaces" will schedule all the taskruns sharing the same PVC-based workspace in a pipelinerun to the same node.
# Setting it to "pipelineruns" will schedule all the taskruns in a pipelinerun to the same node.
# Setting it to "isolate-pipelinerun" will schedule all the taskruns in a pipelinerun to the same node,
# and only allows one pipelinerun to run on a node at a time.
# Setting it to "disabled" will not apply any coschedule policy.
#
# TODO: add links to documentation and migration strategy
# NOTE: this feature is still under development and not yet functional.
coschedule: "workspaces"
# Setting this flag to "true" will prevent Tekton scanning attached
# service accounts and injecting any credentials it finds into your
# Steps.
Expand Down
38 changes: 38 additions & 0 deletions pkg/apis/config/feature_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ const (
// IgnoreNoMatchPolicy is the value used for "trusted-resources-verification-no-match-policy" to skip verification
// when no matching policies are found
IgnoreNoMatchPolicy = "ignore"
// CoscheduleWorkspaces is the value used for "coschedule" to coschedule PipelineRun Pods sharing the same PVC workspaces to the same node
CoscheduleWorkspaces = "workspaces"
// CoschedulePipelineRuns is the value used for "coschedule" to coschedule all PipelineRun Pods to the same node
CoschedulePipelineRuns = "pipelineruns"
// CoscheduleIsolatePipelineRun is the value used for "coschedule" to coschedule all PipelineRun Pods to the same node, and only allows one PipelineRun to run on a node at a time
CoscheduleIsolatePipelineRun = "isolate-pipelinerun"
// CoscheduleDisabled is the value used for "coschedule" to disabled PipelineRun Pods coschedule
CoscheduleDisabled = "disabled"
// ResultExtractionMethodTerminationMessage is the value used for "results-from" as a way to extract results from tasks using kubernetes termination message.
ResultExtractionMethodTerminationMessage = "termination-message"
// ResultExtractionMethodSidecarLogs is the value used for "results-from" as a way to extract results from tasks using sidecar logs.
Expand Down Expand Up @@ -78,6 +86,8 @@ const (
DefaultMaxResultSize = 4096
// DefaultSetSecurityContext is the default value for "set-security-context"
DefaultSetSecurityContext = false
// DefaultCoschedule is the default value for coschedule
DefaultCoschedule = CoscheduleWorkspaces

disableAffinityAssistantKey = "disable-affinity-assistant"
disableCredsInitKey = "disable-creds-init"
Expand All @@ -93,6 +103,7 @@ const (
resultExtractionMethod = "results-from"
maxResultSize = "max-result-size"
setSecurityContextKey = "set-security-context"
coscheduleKey = "coschedule"
)

// DefaultFeatureFlags holds all the default configurations for the feature flags configmap.
Expand Down Expand Up @@ -123,6 +134,7 @@ type FeatureFlags struct {
ResultExtractionMethod string
MaxResultSize int
SetSecurityContext bool
Coschedule string
}

// GetFeatureFlagsConfigName returns the name of the configmap containing all
Expand Down Expand Up @@ -190,6 +202,9 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
return nil, err
}

if err := setCoschedule(cfgMap, DefaultCoschedule, tc.DisableAffinityAssistant, &tc.Coschedule); 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.
Expand Down Expand Up @@ -222,6 +237,29 @@ func setEnabledAPIFields(cfgMap map[string]string, defaultValue string, feature
return nil
}

// setCoschedule sets the "coschedule" flag based on the content of a given map.
// If the feature gate is invalid or incompatible with `disable-affinity-assistant`, then an error is returned.
func setCoschedule(cfgMap map[string]string, defaultValue string, disabledAffinityAssistant bool, feature *string) error {
value := defaultValue
if cfg, ok := cfgMap[coscheduleKey]; ok {
value = strings.ToLower(cfg)
}

switch value {
case CoscheduleDisabled, CoscheduleWorkspaces, CoschedulePipelineRuns, CoscheduleIsolatePipelineRun:
// validate that "coschedule" is compatible with "disable-affinity-assistant"
// "coschedule" must be set to "workspaces" when "disable-affinity-assistant" is false
if !disabledAffinityAssistant && value != CoscheduleWorkspaces {
return fmt.Errorf("coschedule value %v is incompatible with %v setting to false", value, disableAffinityAssistantKey)
}
*feature = value
default:
return fmt.Errorf("invalid value for feature flag %q: %q", coscheduleKey, value)
}

return nil
}

// setEnforceNonFalsifiability sets the "enforce-nonfalsifiability" flag based on the content of a given map.
// If the feature gate is invalid, then an error is returned.
func setEnforceNonFalsifiability(cfgMap map[string]string, enableAPIFields string, feature *string) error {
Expand Down
14 changes: 14 additions & 0 deletions pkg/apis/config/feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: config.GetFeatureFlagsConfigName(),
},
Expand All @@ -70,6 +71,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: "termination-message",
MaxResultSize: 4096,
SetSecurityContext: true,
Coschedule: config.CoscheduleDisabled,
},
fileName: "feature-flags-all-flags-set",
},
Expand All @@ -91,6 +93,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: "feature-flags-enable-api-fields-overrides-bundles-and-custom-tasks",
},
Expand All @@ -110,6 +113,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: "feature-flags-bundles-and-custom-tasks",
},
Expand All @@ -129,6 +133,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: "feature-flags-beta-api-fields",
},
Expand All @@ -144,6 +149,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: "feature-flags-enforce-nonfalsifiability-spire",
},
Expand All @@ -157,6 +163,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
ResultExtractionMethod: config.ResultExtractionMethodSidecarLogs,
MaxResultSize: 8192,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
},
fileName: "feature-flags-results-via-sidecar-logs",
},
Expand Down Expand Up @@ -188,6 +195,7 @@ func TestNewFeatureFlagsFromEmptyConfigMap(t *testing.T) {
ResultExtractionMethod: config.DefaultResultExtractionMethod,
MaxResultSize: config.DefaultMaxResultSize,
SetSecurityContext: config.DefaultSetSecurityContext,
Coschedule: config.DefaultCoschedule,
}
verifyConfigFileWithExpectedFeatureFlagsConfig(t, FeatureFlagsConfigEmptyName, expectedConfig)
}
Expand Down Expand Up @@ -247,6 +255,12 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) {
}, {
fileName: "feature-flags-spire-with-stable",
want: `"enforce-nonfalsifiability" can be set to non-default values ("spire") only in alpha`,
}, {
fileName: "feature-flags-invalid-coschedule-affinity-assistant-comb",
want: `coschedule value pipelineruns is incompatible with disable-affinity-assistant setting to false`,
}, {
fileName: "feature-flags-invalid-coschedule",
want: `invalid value for feature flag "coschedule": "invalid"`,
}} {
t.Run(tc.fileName, func(t *testing.T) {
cm := test.ConfigMapFromTestFile(t, tc.fileName)
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,6 +19,7 @@ metadata:
namespace: tekton-pipelines
data:
disable-affinity-assistant: "true"
coschedule: "disabled"
running-in-environment-with-injected-sidecars: "false"
await-sidecar-readiness: "false"
require-git-ssh-secret-known-hosts: "true"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2023 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
namespace: tekton-pipelines
data:
coschedule: "pipelineruns"
disable-affinity-assistant: "false"
21 changes: 21 additions & 0 deletions pkg/apis/config/testdata/feature-flags-invalid-coschedule.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2023 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
namespace: tekton-pipelines
data:
coschedule: "invalid"
40 changes: 40 additions & 0 deletions pkg/apis/config/testing/featureflags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2023 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
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 testing

import (
"context"
"testing"

"github.com/tektoncd/pipeline/pkg/apis/config"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/logging"
)

// SetFeatureFlags sets the feature-flags ConfigMap values in an existing context (for use in testing)
func SetFeatureFlags(ctx context.Context, t *testing.T, data map[string]string) context.Context {
lbernick marked this conversation as resolved.
Show resolved Hide resolved
t.Helper()
s := config.NewStore(logging.FromContext(ctx).Named("config-store"))
s.OnConfigChanged(&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: config.GetFeatureFlagsConfigName(),
},
Data: data,
})
return s.ToContext(ctx)
}
56 changes: 56 additions & 0 deletions pkg/internal/affinityassistant/affinityassistant_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright 2023 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
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 affinityassistant

import (
"context"
"fmt"

"github.com/tektoncd/pipeline/pkg/apis/config"
)

type AffinityAssitantBehavior string

const (
AffinityAssistantDisabled = AffinityAssitantBehavior("AffinityAssistantDisabled")
AffinityAssistantPerWorkspace = AffinityAssitantBehavior("AffinityAssistantPerWorkspace")
AffinityAssistantPerPipelineRun = AffinityAssitantBehavior("AffinityAssistantPerPipelineRun")
AffinityAssistantPerPipelineRunWithIsolation = AffinityAssitantBehavior("AffinityAssistantPerPipelineRunWithIsolation")
)

// GetAffinityAssistantBehavior returns an AffinityAssitantBehavior based on the
// combination of "disable-affinity-assistant" and "coschedule" feature flags
// TODO(#6740)(WIP): consume this function in the PipelineRun reconciler to determine Affinity Assistant behavior.
lbernick marked this conversation as resolved.
Show resolved Hide resolved
func GetAffinityAssistantBehavior(ctx context.Context) (AffinityAssitantBehavior, error) {
cfg := config.FromContextOrDefaults(ctx)
disableAA := cfg.FeatureFlags.DisableAffinityAssistant
coschedule := cfg.FeatureFlags.Coschedule

// at this point, we have validated that "coschedule" can only be "workspaces"
// when "disable-affinity-assistant" is false
if !disableAA {
return AffinityAssistantPerWorkspace, nil
}

switch coschedule {
case config.CoschedulePipelineRuns:
return AffinityAssistantPerPipelineRun, nil
case config.CoscheduleIsolatePipelineRun:
return AffinityAssistantPerPipelineRunWithIsolation, nil
case config.CoscheduleDisabled, config.CoscheduleWorkspaces:
return AffinityAssistantDisabled, nil
}

return "", fmt.Errorf("unknown combination of disable-affinity-assistant: %v and coschedule: %v", disableAA, coschedule)
}
Loading