diff --git a/config/config-feature-flags.yaml b/config/config-feature-flags.yaml
index dcc52f95c7d..398f37d1880 100644
--- a/config/config-feature-flags.yaml
+++ b/config/config-feature-flags.yaml
@@ -138,3 +138,5 @@ data:
disable-inline-spec: ""
# Setting this flag to "true" will enable the use of concise resolver syntax
enable-concise-resolver-syntax: "false"
+ # Setthing this flag to "true" will enable native Kubernetes Sidecar support
+ enable-kubernetes-sidecar: "false"
diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md
index a2656ffaef2..044799e5a90 100644
--- a/docs/pipeline-api.md
+++ b/docs/pipeline-api.md
@@ -4135,6 +4135,23 @@ other Step or Sidecar that does not also request this Workspace will
not have access to it.
+
+
+restartPolicy
+
+
+Kubernetes core/v1.ContainerRestartPolicy
+
+
+ |
+
+(Optional)
+ RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an
+initContainer and must have it’s policy set to “Always”. It is currently
+left optional to help support Kubernetes versions prior to 1.29 when this feature
+was introduced.
+ |
+
SidecarState
@@ -13459,6 +13476,23 @@ other Step or Sidecar that does not also request this Workspace will
not have access to it.
+
+
+restartPolicy
+
+
+Kubernetes core/v1.ContainerRestartPolicy
+
+
+ |
+
+(Optional)
+ RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an
+initContainer and must have it’s policy set to “Always”. It is currently
+left optional to help support Kubernetes versions prior to 1.29 when this feature
+was introduced.
+ |
+
SidecarState
diff --git a/examples/v1/taskruns/sidecar-ready.yaml b/examples/v1/taskruns/sidecar-ready.yaml
index 20116680dd9..cbba245b934 100644
--- a/examples/v1/taskruns/sidecar-ready.yaml
+++ b/examples/v1/taskruns/sidecar-ready.yaml
@@ -18,6 +18,15 @@ spec:
- -c
- sleep 5 && touch /shared/ready
timeoutSeconds: 10
+ # Adding startup probe for k8s native sidecar support
+ # Readiness Probe is not honored for k8s native sidecar support
+ startupProbe:
+ exec:
+ command:
+ - sh
+ - -c
+ - sleep 5 && touch /shared/ready
+ timeoutSeconds: 10
volumeMounts:
- name: shared
mountPath: /shared
diff --git a/go.mod b/go.mod
index d3eec4c37eb..5af9341e3bd 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,7 @@
module github.com/tektoncd/pipeline
-go 1.22
+go 1.22.3
+
toolchain go1.22.4
require (
diff --git a/pkg/apis/config/feature_flags.go b/pkg/apis/config/feature_flags.go
index 69b80754297..d0db62052cf 100644
--- a/pkg/apis/config/feature_flags.go
+++ b/pkg/apis/config/feature_flags.go
@@ -108,6 +108,10 @@ const (
EnableParamEnum = "enable-param-enum"
// EnableConciseResolverSyntax is the flag to enable concise resolver syntax
EnableConciseResolverSyntax = "enable-concise-resolver-syntax"
+ // EnableKubernetesSidecar is the flag to enable kubernetes sidecar support
+ EnableKubernetesSidecar = "enable-kubernetes-sidecar"
+ // DefaultEnableKubernetesSidecar is the default value for EnableKubernetesSidecar
+ DefaultEnableKubernetesSidecar = false
// DisableInlineSpec is the flag to disable embedded spec
// in Taskrun or Pipelinerun
@@ -208,6 +212,7 @@ type FeatureFlags struct {
EnableArtifacts bool
DisableInlineSpec string
EnableConciseResolverSyntax bool
+ EnableKubernetesSidecar bool
}
// GetFeatureFlagsConfigName returns the name of the configmap containing all
@@ -312,6 +317,9 @@ func NewFeatureFlagsFromMap(cfgMap map[string]string) (*FeatureFlags, error) {
if err := setPerFeatureFlag(EnableConciseResolverSyntax, DefaultEnableConciseResolverSyntax, &tc.EnableConciseResolverSyntax); err != nil {
return nil, err
}
+ if err := setFeature(EnableKubernetesSidecar, DefaultEnableKubernetesSidecar, &tc.EnableKubernetesSidecar); 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 b9e6a588348..cea3e7a5a87 100644
--- a/pkg/apis/config/feature_flags_test.go
+++ b/pkg/apis/config/feature_flags_test.go
@@ -83,6 +83,7 @@ func TestNewFeatureFlagsFromConfigMap(t *testing.T) {
EnableParamEnum: true,
DisableInlineSpec: "pipeline,pipelinerun,taskrun",
EnableConciseResolverSyntax: true,
+ EnableKubernetesSidecar: true,
},
fileName: "feature-flags-all-flags-set",
},
@@ -314,6 +315,9 @@ func TestNewFeatureFlagsConfigMapErrors(t *testing.T) {
}, {
fileName: "feature-flags-invalid-enable-concise-resolver-syntax",
want: `failed parsing feature flags config "invalid": strconv.ParseBool: parsing "invalid": invalid syntax for feature enable-concise-resolver-syntax`,
+ }, {
+ fileName: "feature-flags-invalid-enable-kubernetes-sidecar",
+ want: `failed parsing feature flags config "invalid": strconv.ParseBool: parsing "invalid": invalid syntax for feature enable-kubernetes-sidecar`,
}} {
t.Run(tc.fileName, func(t *testing.T) {
cm := test.ConfigMapFromTestFile(t, tc.fileName)
diff --git a/pkg/apis/config/testdata/feature-flags-invalid-enable-kubernetes-sidecar.yaml b/pkg/apis/config/testdata/feature-flags-invalid-enable-kubernetes-sidecar.yaml
new file mode 100644
index 00000000000..cc78bf080d8
--- /dev/null
+++ b/pkg/apis/config/testdata/feature-flags-invalid-enable-kubernetes-sidecar.yaml
@@ -0,0 +1,21 @@
+# Copyright 2024 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:
+ enable-kubernetes-sidecar: "invalid"
diff --git a/pkg/apis/pipeline/v1/container_types.go b/pkg/apis/pipeline/v1/container_types.go
index 51e9f18717d..b730c7e2fcb 100644
--- a/pkg/apis/pipeline/v1/container_types.go
+++ b/pkg/apis/pipeline/v1/container_types.go
@@ -543,10 +543,43 @@ type Sidecar struct {
// +optional
// +listType=atomic
Workspaces []WorkspaceUsage `json:"workspaces,omitempty"`
+
+ // RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an
+ // initContainer and must have it's policy set to "Always". It is currently
+ // left optional to help support Kubernetes versions prior to 1.29 when this feature
+ // was introduced.
+ // +optional
+ RestartPolicy *corev1.ContainerRestartPolicy `json:"restartPolicy,omitempty"`
}
// ToK8sContainer converts the Sidecar to a Kubernetes Container struct
func (s *Sidecar) ToK8sContainer() *corev1.Container {
+ if s.RestartPolicy == nil {
+ return &corev1.Container{
+ Name: s.Name,
+ Image: s.Image,
+ Command: s.Command,
+ Args: s.Args,
+ WorkingDir: s.WorkingDir,
+ Ports: s.Ports,
+ EnvFrom: s.EnvFrom,
+ Env: s.Env,
+ Resources: s.ComputeResources,
+ VolumeMounts: s.VolumeMounts,
+ VolumeDevices: s.VolumeDevices,
+ LivenessProbe: s.LivenessProbe,
+ ReadinessProbe: s.ReadinessProbe,
+ StartupProbe: s.StartupProbe,
+ Lifecycle: s.Lifecycle,
+ TerminationMessagePath: s.TerminationMessagePath,
+ TerminationMessagePolicy: s.TerminationMessagePolicy,
+ ImagePullPolicy: s.ImagePullPolicy,
+ SecurityContext: s.SecurityContext,
+ Stdin: s.Stdin,
+ StdinOnce: s.StdinOnce,
+ TTY: s.TTY,
+ }
+ }
return &corev1.Container{
Name: s.Name,
Image: s.Image,
@@ -561,6 +594,7 @@ func (s *Sidecar) ToK8sContainer() *corev1.Container {
VolumeDevices: s.VolumeDevices,
LivenessProbe: s.LivenessProbe,
ReadinessProbe: s.ReadinessProbe,
+ RestartPolicy: s.RestartPolicy,
StartupProbe: s.StartupProbe,
Lifecycle: s.Lifecycle,
TerminationMessagePath: s.TerminationMessagePath,
@@ -587,7 +621,7 @@ func (s *Sidecar) SetContainerFields(c corev1.Container) {
s.VolumeMounts = c.VolumeMounts
s.VolumeDevices = c.VolumeDevices
s.LivenessProbe = c.LivenessProbe
- s.ReadinessProbe = c.ReadinessProbe
+ s.ReadinessProbe = c.ReadinessProbe // May need to move this into if statement
s.StartupProbe = c.StartupProbe
s.Lifecycle = c.Lifecycle
s.TerminationMessagePath = c.TerminationMessagePath
@@ -597,6 +631,7 @@ func (s *Sidecar) SetContainerFields(c corev1.Container) {
s.Stdin = c.Stdin
s.StdinOnce = c.StdinOnce
s.TTY = c.TTY
+ s.RestartPolicy = c.RestartPolicy
}
// GetVarSubstitutionExpressions walks all the places a substitution reference can be used
diff --git a/pkg/apis/pipeline/v1/container_types_test.go b/pkg/apis/pipeline/v1/container_types_test.go
index 06948f9acaa..fd7c558eafa 100644
--- a/pkg/apis/pipeline/v1/container_types_test.go
+++ b/pkg/apis/pipeline/v1/container_types_test.go
@@ -120,3 +120,35 @@ func TestSidecarGetVarSubstitutionExpressions(t *testing.T) {
t.Fatalf("Unexpected result (-want, +got): %s", d)
}
}
+
+func TestSidecarRestartPolicyToK8sContainer(t *testing.T) {
+ always := corev1.ContainerRestartPolicyAlways
+ s := Sidecar{
+ Name: "sidecarName",
+ RestartPolicy: &always,
+ }
+
+ expectedContainer := corev1.Container{
+ Name: "sidecarName",
+ RestartPolicy: &always,
+ }
+
+ c := s.ToK8sContainer()
+
+ if !(c.RestartPolicy == expectedContainer.RestartPolicy) {
+ t.Fatalf("Unexpected result with RestartPolicy")
+ }
+
+ s = Sidecar{
+ Name: "sidecarName",
+ }
+
+ expectedContainer = corev1.Container{
+ Name: "sidecarName",
+ }
+
+ c = s.ToK8sContainer()
+ if !(c.RestartPolicy == expectedContainer.RestartPolicy) {
+ t.Fatalf("Unexpected result without RestartPolicy")
+ }
+}
diff --git a/pkg/apis/pipeline/v1/openapi_generated.go b/pkg/apis/pipeline/v1/openapi_generated.go
index 928f446c294..212bbe88928 100644
--- a/pkg/apis/pipeline/v1/openapi_generated.go
+++ b/pkg/apis/pipeline/v1/openapi_generated.go
@@ -2745,6 +2745,13 @@ func schema_pkg_apis_pipeline_v1_Sidecar(ref common.ReferenceCallback) common.Op
},
},
},
+ "restartPolicy": {
+ SchemaProps: spec.SchemaProps{
+ Description: "RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an initContainer and must have it's policy set to \"Always\". It is currently left optional to help support Kubernetes versions prior to 1.29 when this feature was introduced.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
},
Required: []string{"name"},
},
diff --git a/pkg/apis/pipeline/v1/swagger.json b/pkg/apis/pipeline/v1/swagger.json
index 4ece3c37804..b5ee9828ec9 100644
--- a/pkg/apis/pipeline/v1/swagger.json
+++ b/pkg/apis/pipeline/v1/swagger.json
@@ -1325,6 +1325,10 @@
"description": "Periodic probe of Sidecar service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes",
"$ref": "#/definitions/v1.Probe"
},
+ "restartPolicy": {
+ "description": "RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an initContainer and must have it's policy set to \"Always\". It is currently left optional to help support Kubernetes versions prior to 1.29 when this feature was introduced.",
+ "type": "string"
+ },
"script": {
"description": "Script is the contents of an executable file to execute.\n\nIf Script is not empty, the Step cannot have an Command or Args.",
"type": "string"
diff --git a/pkg/apis/pipeline/v1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1/zz_generated.deepcopy.go
index 5b8ca4bb07c..80430b4de73 100644
--- a/pkg/apis/pipeline/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/pipeline/v1/zz_generated.deepcopy.go
@@ -1248,6 +1248,11 @@ func (in *Sidecar) DeepCopyInto(out *Sidecar) {
*out = make([]WorkspaceUsage, len(*in))
copy(*out, *in)
}
+ if in.RestartPolicy != nil {
+ in, out := &in.RestartPolicy, &out.RestartPolicy
+ *out = new(corev1.ContainerRestartPolicy)
+ **out = **in
+ }
return
}
diff --git a/pkg/apis/pipeline/v1beta1/container_types.go b/pkg/apis/pipeline/v1beta1/container_types.go
index 26e08e69fe9..95f852bf496 100644
--- a/pkg/apis/pipeline/v1beta1/container_types.go
+++ b/pkg/apis/pipeline/v1beta1/container_types.go
@@ -747,10 +747,43 @@ type Sidecar struct {
// +optional
// +listType=atomic
Workspaces []WorkspaceUsage `json:"workspaces,omitempty"`
+
+ // RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an
+ // initContainer and must have it's policy set to "Always". It is currently
+ // left optional to help support Kubernetes versions prior to 1.29 when this feature
+ // was introduced.
+ // +optional
+ RestartPolicy *corev1.ContainerRestartPolicy `json:"restartPolicy,omitempty"`
}
// ToK8sContainer converts the Sidecar to a Kubernetes Container struct
func (s *Sidecar) ToK8sContainer() *corev1.Container {
+ if s.RestartPolicy == nil {
+ return &corev1.Container{
+ Name: s.Name,
+ Image: s.Image,
+ Command: s.Command,
+ Args: s.Args,
+ WorkingDir: s.WorkingDir,
+ Ports: s.Ports,
+ EnvFrom: s.EnvFrom,
+ Env: s.Env,
+ Resources: s.Resources,
+ VolumeMounts: s.VolumeMounts,
+ VolumeDevices: s.VolumeDevices,
+ LivenessProbe: s.LivenessProbe,
+ ReadinessProbe: s.ReadinessProbe,
+ StartupProbe: s.StartupProbe,
+ Lifecycle: s.Lifecycle,
+ TerminationMessagePath: s.TerminationMessagePath,
+ TerminationMessagePolicy: s.TerminationMessagePolicy,
+ ImagePullPolicy: s.ImagePullPolicy,
+ SecurityContext: s.SecurityContext,
+ Stdin: s.Stdin,
+ StdinOnce: s.StdinOnce,
+ TTY: s.TTY,
+ }
+ }
return &corev1.Container{
Name: s.Name,
Image: s.Image,
@@ -765,6 +798,7 @@ func (s *Sidecar) ToK8sContainer() *corev1.Container {
VolumeDevices: s.VolumeDevices,
LivenessProbe: s.LivenessProbe,
ReadinessProbe: s.ReadinessProbe,
+ RestartPolicy: s.RestartPolicy,
StartupProbe: s.StartupProbe,
Lifecycle: s.Lifecycle,
TerminationMessagePath: s.TerminationMessagePath,
@@ -801,4 +835,5 @@ func (s *Sidecar) SetContainerFields(c corev1.Container) {
s.Stdin = c.Stdin
s.StdinOnce = c.StdinOnce
s.TTY = c.TTY
+ s.RestartPolicy = c.RestartPolicy
}
diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go
index dde2863832c..65a8e49823a 100644
--- a/pkg/apis/pipeline/v1beta1/openapi_generated.go
+++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go
@@ -3616,6 +3616,13 @@ func schema_pkg_apis_pipeline_v1beta1_Sidecar(ref common.ReferenceCallback) comm
},
},
},
+ "restartPolicy": {
+ SchemaProps: spec.SchemaProps{
+ Description: "RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an initContainer and must have it's policy set to \"Always\". It is currently left optional to help support Kubernetes versions prior to 1.29 when this feature was introduced.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
},
Required: []string{"name"},
},
diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json
index e17ab8e0f33..87df8750801 100644
--- a/pkg/apis/pipeline/v1beta1/swagger.json
+++ b/pkg/apis/pipeline/v1beta1/swagger.json
@@ -1932,6 +1932,10 @@
"default": {},
"$ref": "#/definitions/v1.ResourceRequirements"
},
+ "restartPolicy": {
+ "description": "RestartPolicy refers to kubernetes RestartPolicy. It can only be set for an initContainer and must have it's policy set to \"Always\". It is currently left optional to help support Kubernetes versions prior to 1.29 when this feature was introduced.",
+ "type": "string"
+ },
"script": {
"description": "Script is the contents of an executable file to execute.\n\nIf Script is not empty, the Step cannot have an Command or Args.",
"type": "string"
diff --git a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go
index e2e55e8f8d9..bb9fbaa35ec 100644
--- a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go
@@ -1696,6 +1696,11 @@ func (in *Sidecar) DeepCopyInto(out *Sidecar) {
*out = make([]WorkspaceUsage, len(*in))
copy(*out, *in)
}
+ if in.RestartPolicy != nil {
+ in, out := &in.RestartPolicy, &out.RestartPolicy
+ *out = new(corev1.ContainerRestartPolicy)
+ **out = **in
+ }
return
}
diff --git a/pkg/pod/pod.go b/pkg/pod/pod.go
index 8e808cb6abc..ec530060e20 100644
--- a/pkg/pod/pod.go
+++ b/pkg/pod/pod.go
@@ -74,6 +74,11 @@ const (
// TerminationReasonCancelled indicates a step was cancelled.
TerminationReasonCancelled = "Cancelled"
+
+ StepArtifactPathPattern = "step.artifacts.path"
+
+ // K8s version to determine if to use native k8s sidecar or Tekton sidecar
+ SidecarK8sMinorVersionCheck = 29
)
// These are effectively const, but Go doesn't have such an annotation.
@@ -174,6 +179,13 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1.TaskRun, taskSpec v1.Ta
enableKeepPodOnCancel := featureFlags.EnableKeepPodOnCancel
setSecurityContext := config.FromContextOrDefaults(ctx).FeatureFlags.SetSecurityContext
+ // Kubernetes Version
+ dc := b.KubeClient.Discovery()
+ sv, err := dc.ServerVersion()
+ if err != nil {
+ return nil, err
+ }
+
// Add our implicit volumes first, so they can be overridden by the user if they prefer.
volumes = append(volumes, implicitVolumes...)
volumeMounts = append(volumeMounts, implicitVolumeMounts...)
@@ -426,11 +438,29 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1.TaskRun, taskSpec v1.Ta
}
mergedPodContainers := stepContainers
-
- // Merge sidecar containers with step containers.
- for _, sc := range sidecarContainers {
- sc.Name = names.SimpleNameGenerator.RestrictLength(fmt.Sprintf("%v%v", sidecarPrefix, sc.Name))
- mergedPodContainers = append(mergedPodContainers, sc)
+ mergedPodInitContainers := initContainers
+
+ // Check if current k8s version is less than 1.29
+ // Since Kubernetes Major version cannot be 0 and if it's 2 then sidecar will be in
+ // we are only concerned about major version 1 and if the minor is less than 29 then
+ // we need to do the current logic
+ svMinorInt, _ := strconv.Atoi(sv.Minor)
+ svMajorInt, _ := strconv.Atoi(sv.Major)
+ if svMajorInt >= 1 && svMinorInt >= SidecarK8sMinorVersionCheck {
+ // Add RestartPolicy and Merge into initContainer
+ for i := range sidecarContainers {
+ sc := &sidecarContainers[i]
+ always := corev1.ContainerRestartPolicyAlways
+ sc.RestartPolicy = &always
+ sc.Name = names.SimpleNameGenerator.RestrictLength(fmt.Sprintf("%v%v", sidecarPrefix, sc.Name))
+ mergedPodInitContainers = append(mergedPodInitContainers, *sc)
+ }
+ } else {
+ // Merge sidecar containers with step containers.
+ for _, sc := range sidecarContainers {
+ sc.Name = names.SimpleNameGenerator.RestrictLength(fmt.Sprintf("%v%v", sidecarPrefix, sc.Name))
+ mergedPodContainers = append(mergedPodContainers, sc)
+ }
}
var dnsPolicy corev1.DNSPolicy
@@ -479,7 +509,7 @@ func (b *Builder) Build(ctx context.Context, taskRun *v1.TaskRun, taskSpec v1.Ta
},
Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyNever,
- InitContainers: initContainers,
+ InitContainers: mergedPodInitContainers,
Containers: mergedPodContainers,
ServiceAccountName: taskRun.Spec.ServiceAccountName,
Volumes: volumes,
diff --git a/pkg/pod/pod_test.go b/pkg/pod/pod_test.go
index 2917333a4f1..6a1744681d8 100644
--- a/pkg/pod/pod_test.go
+++ b/pkg/pod/pod_test.go
@@ -37,6 +37,8 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/version"
+ fakediscovery "k8s.io/client-go/discovery/fake"
fakek8s "k8s.io/client-go/kubernetes/fake"
"knative.dev/pkg/apis"
duckv1 "knative.dev/pkg/apis/duck/v1"
@@ -3998,3 +4000,138 @@ func Test_artifactsPathReferenced(t *testing.T) {
})
}
}
+
+func TestPodBuildWithK8s129(t *testing.T) {
+ always := corev1.ContainerRestartPolicyAlways
+ ts := v1.TaskSpec{
+ Steps: []v1.Step{{
+ Name: "name",
+ Image: "image",
+ Command: []string{"cmd"}, // avoid entrypoint lookup.
+ }},
+ Sidecars: []v1.Sidecar{{
+ Name: "name",
+ Image: "image",
+ Command: []string{"cmd"},
+ }},
+ }
+ want := &corev1.PodSpec{
+ RestartPolicy: corev1.RestartPolicyNever,
+ InitContainers: []corev1.Container{
+ entrypointInitContainer(
+ images.EntrypointImage,
+ []v1.Step{{Name: "name"}},
+ false, /* setSecurityContext */
+ false /* windows */),
+ {
+ Name: "sidecar-name",
+ Image: "image",
+ Command: []string{"/tekton/bin/entrypoint"},
+ Args: []string{
+ "-wait_file",
+ "/tekton/downward/ready",
+ "-wait_file_content",
+ "-post_file",
+ "/tekton/run/0/out",
+ "-termination_path",
+ "/tekton/termination",
+ "-step_metadata_dir",
+ "/tekton/run/0/status",
+ "-entrypoint",
+ "cmd",
+ "--",
+ },
+ RestartPolicy: &always,
+ },
+ },
+ Containers: []corev1.Container{{
+ Name: "step-name",
+ Image: "image",
+ Command: []string{"/tekton/bin/entrypoint"},
+ Args: []string{
+ "-wait_file",
+ "/tekton/downward/ready",
+ "-wait_file_content",
+ "-post_file",
+ "/tekton/run/0/out",
+ "-termination_path",
+ "/tekton/termination",
+ "-step_metadata_dir",
+ "/tekton/run/0/status",
+ "-entrypoint",
+ "cmd",
+ "--",
+ },
+ }},
+ }
+
+ store := config.NewStore(logtesting.TestLogger(t))
+ store.OnConfigChanged(
+ &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{Name: config.GetFeatureFlagsConfigName(), Namespace: system.Namespace()},
+ },
+ )
+ kubeclient := fakek8s.NewSimpleClientset(
+ &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}},
+ &corev1.ServiceAccount{
+ ObjectMeta: metav1.ObjectMeta{Name: "service-account", Namespace: "default"},
+ Secrets: []corev1.ObjectReference{{
+ Name: "multi-creds",
+ }},
+ },
+ &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "multi-creds",
+ Namespace: "default",
+ Annotations: map[string]string{
+ "tekton.dev/docker-0": "https://us.gcr.io",
+ "tekton.dev/docker-1": "https://docker.io",
+ "tekton.dev/git-0": "github.com",
+ "tekton.dev/git-1": "gitlab.com",
+ },
+ },
+ Type: "kubernetes.io/basic-auth",
+ Data: map[string][]byte{
+ "username": []byte("foo"),
+ "password": []byte("BestEver"),
+ },
+ },
+ )
+ fakeDisc, _ := kubeclient.Discovery().(*fakediscovery.FakeDiscovery)
+ fakeDisc.FakedServerVersion = &version.Info{
+ Major: "1",
+ Minor: "29",
+ }
+
+ trs := v1.TaskRunSpec{
+ TaskSpec: &ts,
+ }
+
+ tr := &v1.TaskRun{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "taskrunName",
+ Namespace: "default",
+ },
+ Spec: trs,
+ }
+
+ // No entrypoints should be looked up.
+ entrypointCache := fakeCache{}
+
+ builder := Builder{
+ Images: images,
+ KubeClient: kubeclient,
+ EntrypointCache: entrypointCache,
+ }
+ got, err := builder.Build(store.ToContext(context.Background()), tr, ts)
+ if err != nil {
+ t.Errorf("Pod build failed: %s", err)
+ }
+ if d := cmp.Diff(want.InitContainers[1].Name, got.Spec.InitContainers[1].Name); d != "" {
+ t.Errorf("Pod does not have sidecar in init list: %s", diff.PrintWantGot(d))
+ }
+
+ if d := cmp.Diff(want.InitContainers[1].RestartPolicy, got.Spec.InitContainers[1].RestartPolicy); d != "" {
+ t.Errorf("Sidecar does not have RestartPolicy Always: %s", diff.PrintWantGot(d))
+ }
+}
diff --git a/pkg/pod/status.go b/pkg/pod/status.go
index bee46ebcf90..c0db895fe43 100644
--- a/pkg/pod/status.go
+++ b/pkg/pod/status.go
@@ -151,6 +151,11 @@ func MakeTaskRunStatus(ctx context.Context, logger *zap.SugaredLogger, tr v1.Tas
sidecarStatuses = append(sidecarStatuses, s)
}
}
+ for _, s := range pod.Status.InitContainerStatuses {
+ if IsContainerSidecar(s.Name) {
+ sidecarStatuses = append(sidecarStatuses, s)
+ }
+ }
var merr *multierror.Error
if err := setTaskRunStatusBasedOnStepStatus(ctx, logger, stepStatuses, &tr, pod.Status.Phase, kubeclient, ts); err != nil {
diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go
index b51daad6e11..47963d0b6a6 100644
--- a/pkg/reconciler/taskrun/taskrun.go
+++ b/pkg/reconciler/taskrun/taskrun.go
@@ -22,6 +22,7 @@ import (
"fmt"
"reflect"
"slices"
+ "strconv"
"strings"
"time"
@@ -152,9 +153,24 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, tr *v1.TaskRun) pkgrecon
// and may not have had all of the assumed default specified.
tr.SetDefaults(ctx)
- if err := c.stopSidecars(ctx, tr); err != nil {
+ // Check if current k8s version is less than 1.29
+ // Since Kubernetes Major version cannot be 0 and if it's 2 then sidecar will be in
+ // we are only concerned about major version 1 and if the minor is less than 29 then
+ // we need to do the current logic
+ dc := c.KubeClientSet.Discovery()
+ sv, err := dc.ServerVersion()
+ if err != nil {
return err
}
+ svMajorInt, _ := strconv.Atoi(sv.Major)
+ svMinorInt, _ := strconv.Atoi(sv.Minor)
+ if svMajorInt >= 1 && svMinorInt >= 29 {
+ logger.Infof("Using Kubernetes Native Sidecars \n")
+ } else {
+ if err := c.stopSidecars(ctx, tr); err != nil {
+ return err
+ }
+ }
return c.finishReconcileUpdateEmitEvents(ctx, tr, before, nil)
}
diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go
index 282ac982151..568a95094bd 100644
--- a/pkg/reconciler/taskrun/taskrun_test.go
+++ b/pkg/reconciler/taskrun/taskrun_test.go
@@ -2316,7 +2316,7 @@ status:
// Check actions
actions := clients.Kube.Actions()
- if len(actions) != 2 || !actions[0].Matches("list", "configmaps") || !actions[1].Matches("watch", "configmaps") {
+ if len(actions) != 3 || !actions[0].Matches("list", "configmaps") || !actions[1].Matches("watch", "configmaps") || !actions[2].Matches("get", "version") {
t.Errorf("expected 2 actions (list configmaps, and watch configmaps) created by the reconciler,"+
" got %d. Actions: %#v", len(actions), actions)
}
diff --git a/test/e2e-tests-kind-prow-alpha.env b/test/e2e-tests-kind-prow-alpha.env
index dfcc2e76444..5ab894c2ac7 100644
--- a/test/e2e-tests-kind-prow-alpha.env
+++ b/test/e2e-tests-kind-prow-alpha.env
@@ -9,3 +9,4 @@ ENABLE_CEL_IN_WHENEXPRESSION=true
ENABLE_PARAM_ENUM=true
ENABLE_ARTIFACTS=true
ENABLE_CONCISE_RESOLVER_SYNTAX=true
+ENABLE_KUBERNETES_SIDECAR=true
diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh
index 8a8b63a48eb..9d78515fdb5 100755
--- a/test/e2e-tests.sh
+++ b/test/e2e-tests.sh
@@ -33,6 +33,7 @@ ENABLE_CEL_IN_WHENEXPRESSION=${ENABLE_CEL_IN_WHENEXPRESSION:="false"}
ENABLE_PARAM_ENUM=${ENABLE_PARAM_ENUM:="false"}
ENABLE_ARTIFACTS=${ENABLE_ARTIFACTS:="false"}
ENABLE_CONCISE_RESOLVER_SYNTAX=${ENABLE_CONCISE_RESOLVER_SYNTAX:="false"}
+ENABLE_KUBERNETES_SIDECAR=${ENABLE_KUBERNETES_SIDECAR:="false"}
failed=0
# Script entry point.
@@ -143,6 +144,18 @@ function set_enable_concise_resolver_syntax() {
kubectl patch configmap feature-flags -n tekton-pipelines -p "$jsonpatch"
}
+function set_enable_kubernetes_sidecar() {
+ local method="$1"
+ if [ "$method" != "false" ] && [ "$method" != "true" ]; then
+ printf "Invalid value for enable-kubernetes-sidecar %s\n" ${method}
+ exit 255
+ fi
+ printf "Setting enable-kubernetes-sidecar to %s\n", ${method}
+ jsonpatch=$(printf "{\"data\": {\"enable-kubernetes-sidecar\": \"%s\"}}" $1)
+ echo "feature-flags ConfigMap patch: ${jsonpatch}"
+ kubectl patch configmap feature-flags -n tekton-pipelines -p "$jsonpatch"
+}
+
function run_e2e() {
# Run the integration tests
header "Running Go e2e tests"
@@ -171,6 +184,7 @@ set_cel_in_whenexpression "$ENABLE_CEL_IN_WHENEXPRESSION"
set_enable_param_enum "$ENABLE_PARAM_ENUM"
set_enable_artifacts "$ENABLE_ARTIFACTS"
set_enable_concise_resolver_syntax "$ENABLE_CONCISE_RESOLVER_SYNTAX"
+set_enable_kubernetes_sidecar "$ENABLE_KUBERNETES_SIDECAR"
run_e2e
(( failed )) && fail_test