mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Remove EphemeralContainers feature-gate checks
This commit is contained in:
		@@ -46,11 +46,7 @@ const AllContainers ContainerType = (InitContainers | Containers | EphemeralCont
 | 
				
			|||||||
// AllFeatureEnabledContainers returns a ContainerType mask which includes all container
 | 
					// AllFeatureEnabledContainers returns a ContainerType mask which includes all container
 | 
				
			||||||
// types except for the ones guarded by feature gate.
 | 
					// types except for the ones guarded by feature gate.
 | 
				
			||||||
func AllFeatureEnabledContainers() ContainerType {
 | 
					func AllFeatureEnabledContainers() ContainerType {
 | 
				
			||||||
	containerType := AllContainers
 | 
						return AllContainers
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		containerType &= ^EphemeralContainers
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return containerType
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContainerVisitor is called with each container spec, and returns true
 | 
					// ContainerVisitor is called with each container spec, and returns true
 | 
				
			||||||
@@ -529,10 +525,6 @@ func dropDisabledFields(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) && !ephemeralContainersInUse(oldPodSpec) {
 | 
					 | 
				
			||||||
		podSpec.EphemeralContainers = nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) && !probeGracePeriodInUse(oldPodSpec) {
 | 
						if !utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) && !probeGracePeriodInUse(oldPodSpec) {
 | 
				
			||||||
		// Set pod-level terminationGracePeriodSeconds to nil if the feature is disabled and it is not used
 | 
							// Set pod-level terminationGracePeriodSeconds to nil if the feature is disabled and it is not used
 | 
				
			||||||
		VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
 | 
							VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
 | 
				
			||||||
@@ -654,13 +646,6 @@ func nodeTaintsPolicyInUse(podSpec *api.PodSpec) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ephemeralContainersInUse(podSpec *api.PodSpec) bool {
 | 
					 | 
				
			||||||
	if podSpec == nil {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return len(podSpec.EphemeralContainers) > 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// procMountInUse returns true if the pod spec is non-nil and has a SecurityContext's ProcMount field set to a non-default value
 | 
					// procMountInUse returns true if the pod spec is non-nil and has a SecurityContext's ProcMount field set to a non-default value
 | 
				
			||||||
func procMountInUse(podSpec *api.PodSpec) bool {
 | 
					func procMountInUse(podSpec *api.PodSpec) bool {
 | 
				
			||||||
	if podSpec == nil {
 | 
						if podSpec == nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
		spec           *api.PodSpec
 | 
							spec           *api.PodSpec
 | 
				
			||||||
		wantContainers []string
 | 
							wantContainers []string
 | 
				
			||||||
		mask           ContainerType
 | 
							mask           ContainerType
 | 
				
			||||||
		ephemeralContainersEnabled bool
 | 
					 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc:           "empty podspec",
 | 
								desc:           "empty podspec",
 | 
				
			||||||
@@ -127,25 +126,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
			wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
								wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
				
			||||||
			mask:           AllContainers,
 | 
								mask:           AllContainers,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			desc: "all feature enabled container types with ephemeral containers disabled",
 | 
					 | 
				
			||||||
			spec: &api.PodSpec{
 | 
					 | 
				
			||||||
				Containers: []api.Container{
 | 
					 | 
				
			||||||
					{Name: "c1"},
 | 
					 | 
				
			||||||
					{Name: "c2"},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				InitContainers: []api.Container{
 | 
					 | 
				
			||||||
					{Name: "i1"},
 | 
					 | 
				
			||||||
					{Name: "i2"},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				EphemeralContainers: []api.EphemeralContainer{
 | 
					 | 
				
			||||||
					{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
 | 
					 | 
				
			||||||
					{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			wantContainers: []string{"i1", "i2", "c1", "c2"},
 | 
					 | 
				
			||||||
			mask:           setAllFeatureEnabledContainersDuringTest,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc: "all feature enabled container types with ephemeral containers enabled",
 | 
								desc: "all feature enabled container types with ephemeral containers enabled",
 | 
				
			||||||
			spec: &api.PodSpec{
 | 
								spec: &api.PodSpec{
 | 
				
			||||||
@@ -164,7 +144,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
								wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
				
			||||||
			mask:           setAllFeatureEnabledContainersDuringTest,
 | 
								mask:           setAllFeatureEnabledContainersDuringTest,
 | 
				
			||||||
			ephemeralContainersEnabled: true,
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc: "dropping fields",
 | 
								desc: "dropping fields",
 | 
				
			||||||
@@ -189,8 +168,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testCases {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
		t.Run(tc.desc, func(t *testing.T) {
 | 
							t.Run(tc.desc, func(t *testing.T) {
 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, tc.ephemeralContainersEnabled)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if tc.mask == setAllFeatureEnabledContainersDuringTest {
 | 
								if tc.mask == setAllFeatureEnabledContainersDuringTest {
 | 
				
			||||||
				tc.mask = AllFeatureEnabledContainers()
 | 
									tc.mask = AllFeatureEnabledContainers()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -226,8 +203,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodSecrets(t *testing.T) {
 | 
					func TestPodSecrets(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Stub containing all possible secret references in a pod.
 | 
						// Stub containing all possible secret references in a pod.
 | 
				
			||||||
	// The names of the referenced secrets match struct paths detected by reflection.
 | 
						// The names of the referenced secrets match struct paths detected by reflection.
 | 
				
			||||||
	pod := &api.Pod{
 | 
						pod := &api.Pod{
 | 
				
			||||||
@@ -425,8 +400,6 @@ func collectResourcePaths(t *testing.T, resourcename string, path *field.Path, n
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodConfigmaps(t *testing.T) {
 | 
					func TestPodConfigmaps(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Stub containing all possible ConfigMap references in a pod.
 | 
						// Stub containing all possible ConfigMap references in a pod.
 | 
				
			||||||
	// The names of the referenced ConfigMaps match struct paths detected by reflection.
 | 
						// The names of the referenced ConfigMaps match struct paths detected by reflection.
 | 
				
			||||||
	pod := &api.Pod{
 | 
						pod := &api.Pod{
 | 
				
			||||||
@@ -1023,95 +996,6 @@ func TestDropProbeGracePeriod(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDropEphemeralContainers(t *testing.T) {
 | 
					 | 
				
			||||||
	podWithEphemeralContainers := func() *api.Pod {
 | 
					 | 
				
			||||||
		return &api.Pod{
 | 
					 | 
				
			||||||
			Spec: api.PodSpec{
 | 
					 | 
				
			||||||
				RestartPolicy:       api.RestartPolicyNever,
 | 
					 | 
				
			||||||
				EphemeralContainers: []api.EphemeralContainer{{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "container1", Image: "testimage"}}},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	podWithoutEphemeralContainers := func() *api.Pod {
 | 
					 | 
				
			||||||
		return &api.Pod{
 | 
					 | 
				
			||||||
			Spec: api.PodSpec{
 | 
					 | 
				
			||||||
				RestartPolicy: api.RestartPolicyNever,
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	podInfo := []struct {
 | 
					 | 
				
			||||||
		description            string
 | 
					 | 
				
			||||||
		hasEphemeralContainers bool
 | 
					 | 
				
			||||||
		pod                    func() *api.Pod
 | 
					 | 
				
			||||||
	}{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			description:            "has ephemeral containers",
 | 
					 | 
				
			||||||
			hasEphemeralContainers: true,
 | 
					 | 
				
			||||||
			pod:                    podWithEphemeralContainers,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			description:            "does not have ephemeral containers",
 | 
					 | 
				
			||||||
			hasEphemeralContainers: false,
 | 
					 | 
				
			||||||
			pod:                    podWithoutEphemeralContainers,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			description:            "is nil",
 | 
					 | 
				
			||||||
			hasEphemeralContainers: false,
 | 
					 | 
				
			||||||
			pod:                    func() *api.Pod { return nil },
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, enabled := range []bool{true, false} {
 | 
					 | 
				
			||||||
		for _, oldPodInfo := range podInfo {
 | 
					 | 
				
			||||||
			for _, newPodInfo := range podInfo {
 | 
					 | 
				
			||||||
				oldPodHasEphemeralContainers, oldPod := oldPodInfo.hasEphemeralContainers, oldPodInfo.pod()
 | 
					 | 
				
			||||||
				newPodHasEphemeralContainers, newPod := newPodInfo.hasEphemeralContainers, newPodInfo.pod()
 | 
					 | 
				
			||||||
				if newPod == nil {
 | 
					 | 
				
			||||||
					continue
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
 | 
					 | 
				
			||||||
					defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, enabled)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					var oldPodSpec *api.PodSpec
 | 
					 | 
				
			||||||
					if oldPod != nil {
 | 
					 | 
				
			||||||
						oldPodSpec = &oldPod.Spec
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					// old pod should never be changed
 | 
					 | 
				
			||||||
					if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
 | 
					 | 
				
			||||||
						t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					switch {
 | 
					 | 
				
			||||||
					case enabled || oldPodHasEphemeralContainers:
 | 
					 | 
				
			||||||
						// new pod should not be changed if the feature is enabled, or if the old pod had subpaths
 | 
					 | 
				
			||||||
						if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
					 | 
				
			||||||
							t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					case newPodHasEphemeralContainers:
 | 
					 | 
				
			||||||
						// new pod should be changed
 | 
					 | 
				
			||||||
						if reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
					 | 
				
			||||||
							t.Errorf("new pod was not changed")
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
						// new pod should not have subpaths
 | 
					 | 
				
			||||||
						if !reflect.DeepEqual(newPod, podWithoutEphemeralContainers()) {
 | 
					 | 
				
			||||||
							t.Errorf("new pod had subpaths: %v", cmp.Diff(newPod, podWithoutEphemeralContainers()))
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					default:
 | 
					 | 
				
			||||||
						// new pod should not need to be changed
 | 
					 | 
				
			||||||
						if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
 | 
					 | 
				
			||||||
							t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				})
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestValidatePodDeletionCostOption(t *testing.T) {
 | 
					func TestValidatePodDeletionCostOption(t *testing.T) {
 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		name                            string
 | 
							name                            string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,8 +23,6 @@ import (
 | 
				
			|||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
						"k8s.io/apimachinery/pkg/util/intstr"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindPort locates the container port for the given pod and portName.  If the
 | 
					// FindPort locates the container port for the given pod and portName.  If the
 | 
				
			||||||
@@ -68,11 +66,7 @@ const AllContainers ContainerType = (InitContainers | Containers | EphemeralCont
 | 
				
			|||||||
// AllFeatureEnabledContainers returns a ContainerType mask which includes all container
 | 
					// AllFeatureEnabledContainers returns a ContainerType mask which includes all container
 | 
				
			||||||
// types except for the ones guarded by feature gate.
 | 
					// types except for the ones guarded by feature gate.
 | 
				
			||||||
func AllFeatureEnabledContainers() ContainerType {
 | 
					func AllFeatureEnabledContainers() ContainerType {
 | 
				
			||||||
	containerType := AllContainers
 | 
						return AllContainers
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		containerType &= ^EphemeralContainers
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return containerType
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContainerVisitor is called with each container spec, and returns true
 | 
					// ContainerVisitor is called with each container spec, and returns true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,6 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
						"k8s.io/apimachinery/pkg/util/intstr"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
						"k8s.io/apimachinery/pkg/util/validation/field"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFindPort(t *testing.T) {
 | 
					func TestFindPort(t *testing.T) {
 | 
				
			||||||
@@ -209,7 +206,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
		spec           *v1.PodSpec
 | 
							spec           *v1.PodSpec
 | 
				
			||||||
		wantContainers []string
 | 
							wantContainers []string
 | 
				
			||||||
		mask           ContainerType
 | 
							mask           ContainerType
 | 
				
			||||||
		ephemeralContainersEnabled bool
 | 
					 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc:           "empty podspec",
 | 
								desc:           "empty podspec",
 | 
				
			||||||
@@ -294,26 +290,7 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
			mask:           AllContainers,
 | 
								mask:           AllContainers,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc: "all feature enabled container types with ephemeral containers disabled",
 | 
								desc: "all feature enabled container types",
 | 
				
			||||||
			spec: &v1.PodSpec{
 | 
					 | 
				
			||||||
				Containers: []v1.Container{
 | 
					 | 
				
			||||||
					{Name: "c1"},
 | 
					 | 
				
			||||||
					{Name: "c2"},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				InitContainers: []v1.Container{
 | 
					 | 
				
			||||||
					{Name: "i1"},
 | 
					 | 
				
			||||||
					{Name: "i2"},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				EphemeralContainers: []v1.EphemeralContainer{
 | 
					 | 
				
			||||||
					{EphemeralContainerCommon: v1.EphemeralContainerCommon{Name: "e1"}},
 | 
					 | 
				
			||||||
					{EphemeralContainerCommon: v1.EphemeralContainerCommon{Name: "e2"}},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			wantContainers: []string{"i1", "i2", "c1", "c2"},
 | 
					 | 
				
			||||||
			mask:           setAllFeatureEnabledContainersDuringTest,
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			desc: "all feature enabled container types with ephemeral containers enabled",
 | 
					 | 
				
			||||||
			spec: &v1.PodSpec{
 | 
								spec: &v1.PodSpec{
 | 
				
			||||||
				Containers: []v1.Container{
 | 
									Containers: []v1.Container{
 | 
				
			||||||
					{Name: "c1"},
 | 
										{Name: "c1"},
 | 
				
			||||||
@@ -330,7 +307,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
								wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
 | 
				
			||||||
			mask:           setAllFeatureEnabledContainersDuringTest,
 | 
								mask:           setAllFeatureEnabledContainersDuringTest,
 | 
				
			||||||
			ephemeralContainersEnabled: true,
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			desc: "dropping fields",
 | 
								desc: "dropping fields",
 | 
				
			||||||
@@ -355,8 +331,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for _, tc := range testCases {
 | 
						for _, tc := range testCases {
 | 
				
			||||||
		t.Run(tc.desc, func(t *testing.T) {
 | 
							t.Run(tc.desc, func(t *testing.T) {
 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, tc.ephemeralContainersEnabled)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if tc.mask == setAllFeatureEnabledContainersDuringTest {
 | 
								if tc.mask == setAllFeatureEnabledContainersDuringTest {
 | 
				
			||||||
				tc.mask = AllFeatureEnabledContainers()
 | 
									tc.mask = AllFeatureEnabledContainers()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -392,8 +366,6 @@ func TestVisitContainers(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodSecrets(t *testing.T) {
 | 
					func TestPodSecrets(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Stub containing all possible secret references in a pod.
 | 
						// Stub containing all possible secret references in a pod.
 | 
				
			||||||
	// The names of the referenced secrets match struct paths detected by reflection.
 | 
						// The names of the referenced secrets match struct paths detected by reflection.
 | 
				
			||||||
	pod := &v1.Pod{
 | 
						pod := &v1.Pod{
 | 
				
			||||||
@@ -591,8 +563,6 @@ func collectResourcePaths(t *testing.T, resourcename string, path *field.Path, n
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodConfigmaps(t *testing.T) {
 | 
					func TestPodConfigmaps(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Stub containing all possible ConfigMap references in a pod.
 | 
						// Stub containing all possible ConfigMap references in a pod.
 | 
				
			||||||
	// The names of the referenced ConfigMaps match struct paths detected by reflection.
 | 
						// The names of the referenced ConfigMaps match struct paths detected by reflection.
 | 
				
			||||||
	pod := &v1.Pod{
 | 
						pod := &v1.Pod{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2396,8 +2396,6 @@ func TestValidateDaemonSetUpdate(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestValidateDaemonSet(t *testing.T) {
 | 
					func TestValidateDaemonSet(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	validSelector := map[string]string{"a": "b"}
 | 
						validSelector := map[string]string{"a": "b"}
 | 
				
			||||||
	validPodTemplate := api.PodTemplate{
 | 
						validPodTemplate := api.PodTemplate{
 | 
				
			||||||
		Template: api.PodTemplateSpec{
 | 
							Template: api.PodTemplateSpec{
 | 
				
			||||||
@@ -2660,8 +2658,6 @@ func validDeployment() *apps.Deployment {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestValidateDeployment(t *testing.T) {
 | 
					func TestValidateDeployment(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	successCases := []*apps.Deployment{
 | 
						successCases := []*apps.Deployment{
 | 
				
			||||||
		validDeployment(),
 | 
							validDeployment(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,9 +20,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
						"k8s.io/apimachinery/pkg/util/validation/field"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						api "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/fieldpath"
 | 
						"k8s.io/kubernetes/pkg/fieldpath"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,14 +45,12 @@ func VisitContainersWithPath(podSpec *api.PodSpec, specPath *field.Path, visitor
 | 
				
			|||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
	fldPath = specPath.Child("ephemeralContainers")
 | 
						fldPath = specPath.Child("ephemeralContainers")
 | 
				
			||||||
	for i := range podSpec.EphemeralContainers {
 | 
						for i := range podSpec.EphemeralContainers {
 | 
				
			||||||
		if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), fldPath.Index(i)) {
 | 
							if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), fldPath.Index(i)) {
 | 
				
			||||||
			return false
 | 
								return false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,15 +21,10 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
						"k8s.io/apimachinery/pkg/util/validation/field"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						api "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestVisitContainersWithPath(t *testing.T) {
 | 
					func TestVisitContainersWithPath(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	testCases := []struct {
 | 
						testCases := []struct {
 | 
				
			||||||
		description string
 | 
							description string
 | 
				
			||||||
		path        *field.Path
 | 
							path        *field.Path
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11485,8 +11485,6 @@ func makeValidService() core.Service {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestValidatePodEphemeralContainersUpdate(t *testing.T) {
 | 
					func TestValidatePodEphemeralContainersUpdate(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	makePod := func(ephemeralContainers []core.EphemeralContainer) *core.Pod {
 | 
						makePod := func(ephemeralContainers []core.EphemeralContainer) *core.Pod {
 | 
				
			||||||
		return &core.Pod{
 | 
							return &core.Pod{
 | 
				
			||||||
			ObjectMeta: metav1.ObjectMeta{
 | 
								ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
@@ -20312,7 +20310,6 @@ func TestValidateWindowsHostProcessPod(t *testing.T) {
 | 
				
			|||||||
	for _, testCase := range testCases {
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
		t.Run(testCase.name, func(t *testing.T) {
 | 
							t.Run(testCase.name, func(t *testing.T) {
 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WindowsHostProcessContainers, testCase.featureEnabled)()
 | 
								defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.WindowsHostProcessContainers, testCase.featureEnabled)()
 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			opts := PodValidationOptions{AllowWindowsHostProcessField: testCase.featureEnabled}
 | 
								opts := PodValidationOptions{AllowWindowsHostProcessField: testCase.featureEnabled}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,9 +26,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEnvVarsToMap(t *testing.T) {
 | 
					func TestEnvVarsToMap(t *testing.T) {
 | 
				
			||||||
@@ -326,7 +323,6 @@ func TestExpandVolumeMountsWithSubpath(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetContainerSpec(t *testing.T) {
 | 
					func TestGetContainerSpec(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
	for _, tc := range []struct {
 | 
						for _, tc := range []struct {
 | 
				
			||||||
		name          string
 | 
							name          string
 | 
				
			||||||
		havePod       *v1.Pod
 | 
							havePod       *v1.Pod
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,8 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	ref "k8s.io/client-go/tools/reference"
 | 
						ref "k8s.io/client-go/tools/reference"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
						"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ImplicitContainerPrefix is a container name prefix that will indicate that container was started implicitly (like the pod infra container).
 | 
					// ImplicitContainerPrefix is a container name prefix that will indicate that container was started implicitly (like the pod infra container).
 | 
				
			||||||
@@ -67,7 +65,6 @@ func fieldPath(pod *v1.Pod, container *v1.Container) (string, error) {
 | 
				
			|||||||
			return fmt.Sprintf("spec.initContainers{%s}", here.Name), nil
 | 
								return fmt.Sprintf("spec.initContainers{%s}", here.Name), nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
	for i := range pod.Spec.EphemeralContainers {
 | 
						for i := range pod.Spec.EphemeralContainers {
 | 
				
			||||||
		here := &pod.Spec.EphemeralContainers[i]
 | 
							here := &pod.Spec.EphemeralContainers[i]
 | 
				
			||||||
		if here.Name == container.Name {
 | 
							if here.Name == container.Name {
 | 
				
			||||||
@@ -77,6 +74,5 @@ func fieldPath(pod *v1.Pod, container *v1.Container) (string, error) {
 | 
				
			|||||||
			return fmt.Sprintf("spec.ephemeralContainers{%s}", here.Name), nil
 | 
								return fmt.Sprintf("spec.ephemeralContainers{%s}", here.Name), nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return "", fmt.Errorf("container %q not found in pod %s/%s", container.Name, pod.Namespace, pod.Name)
 | 
						return "", fmt.Errorf("container %q not found in pod %s/%s", container.Name, pod.Namespace, pod.Name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1221,7 +1221,7 @@ func (kl *Kubelet) validateContainerLogStatus(podName string, podStatus *v1.PodS
 | 
				
			|||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
		cStatus, found = podutil.GetContainerStatus(podStatus.InitContainerStatuses, containerName)
 | 
							cStatus, found = podutil.GetContainerStatus(podStatus.InitContainerStatuses, containerName)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !found && utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
						if !found {
 | 
				
			||||||
		cStatus, found = podutil.GetContainerStatus(podStatus.EphemeralContainerStatuses, containerName)
 | 
							cStatus, found = podutil.GetContainerStatus(podStatus.EphemeralContainerStatuses, containerName)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !found {
 | 
						if !found {
 | 
				
			||||||
@@ -1602,7 +1602,6 @@ func (kl *Kubelet) convertStatusToAPIStatus(pod *v1.Pod, podStatus *kubecontaine
 | 
				
			|||||||
		len(pod.Spec.InitContainers) > 0,
 | 
							len(pod.Spec.InitContainers) > 0,
 | 
				
			||||||
		true,
 | 
							true,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
	var ecSpecs []v1.Container
 | 
						var ecSpecs []v1.Container
 | 
				
			||||||
	for i := range pod.Spec.EphemeralContainers {
 | 
						for i := range pod.Spec.EphemeralContainers {
 | 
				
			||||||
		ecSpecs = append(ecSpecs, v1.Container(pod.Spec.EphemeralContainers[i].EphemeralContainerCommon))
 | 
							ecSpecs = append(ecSpecs, v1.Container(pod.Spec.EphemeralContainers[i].EphemeralContainerCommon))
 | 
				
			||||||
@@ -1617,7 +1616,6 @@ func (kl *Kubelet) convertStatusToAPIStatus(pod *v1.Pod, podStatus *kubecontaine
 | 
				
			|||||||
		len(pod.Spec.InitContainers) > 0,
 | 
							len(pod.Spec.InitContainers) > 0,
 | 
				
			||||||
		false,
 | 
							false,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &apiPodStatus
 | 
						return &apiPodStatus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,9 +46,7 @@ import (
 | 
				
			|||||||
	kubetypes "k8s.io/apimachinery/pkg/types"
 | 
						kubetypes "k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
						utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
						kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/cri/remote"
 | 
						"k8s.io/kubernetes/pkg/kubelet/cri/remote"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/events"
 | 
						"k8s.io/kubernetes/pkg/kubelet/events"
 | 
				
			||||||
@@ -120,7 +118,7 @@ func ephemeralContainerStartSpec(ec *v1.EphemeralContainer) *startSpec {
 | 
				
			|||||||
// usually isn't a problem since ephemeral containers aren't allowed at pod creation time.
 | 
					// usually isn't a problem since ephemeral containers aren't allowed at pod creation time.
 | 
				
			||||||
// This always returns nil when the EphemeralContainers feature is disabled.
 | 
					// This always returns nil when the EphemeralContainers feature is disabled.
 | 
				
			||||||
func (s *startSpec) getTargetID(podStatus *kubecontainer.PodStatus) (*kubecontainer.ContainerID, error) {
 | 
					func (s *startSpec) getTargetID(podStatus *kubecontainer.PodStatus) (*kubecontainer.ContainerID, error) {
 | 
				
			||||||
	if s.ephemeralContainer == nil || s.ephemeralContainer.TargetContainerName == "" || !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
						if s.ephemeralContainer == nil || s.ephemeralContainer.TargetContainerName == "" {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -520,7 +520,6 @@ func TestGetHugepageLimitsFromResources(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGenerateLinuxContainerConfigNamespaces(t *testing.T) {
 | 
					func TestGenerateLinuxContainerConfigNamespaces(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
	_, _, m, err := createTestRuntimeManager()
 | 
						_, _, m, err := createTestRuntimeManager()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("error creating test RuntimeManager: %v", err)
 | 
							t.Fatalf("error creating test RuntimeManager: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
				
			|||||||
package kuberuntime
 | 
					package kuberuntime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
@@ -32,10 +31,7 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
						kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
				
			||||||
	containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
 | 
						containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/lifecycle"
 | 
						"k8s.io/kubernetes/pkg/kubelet/lifecycle"
 | 
				
			||||||
@@ -405,23 +401,12 @@ func TestStartSpec(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	} {
 | 
						} {
 | 
				
			||||||
		t.Run(tc.name, func(t *testing.T) {
 | 
							t.Run(tc.name, func(t *testing.T) {
 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
			if got, err := tc.spec.getTargetID(podStatus); err != nil {
 | 
								if got, err := tc.spec.getTargetID(podStatus); err != nil {
 | 
				
			||||||
				t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
 | 
									t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
 | 
				
			||||||
			} else if diff := cmp.Diff(tc.want, got); diff != "" {
 | 
								} else if diff := cmp.Diff(tc.want, got); diff != "" {
 | 
				
			||||||
				t.Errorf("%v: getTargetID got unexpected result. diff:\n%v", t.Name(), diff)
 | 
									t.Errorf("%v: getTargetID got unexpected result. diff:\n%v", t.Name(), diff)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Test with feature disabled in self-contained section which can be removed when feature flag is removed.
 | 
					 | 
				
			||||||
		t.Run(fmt.Sprintf("%s (disabled)", tc.name), func(t *testing.T) {
 | 
					 | 
				
			||||||
			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, false)()
 | 
					 | 
				
			||||||
			if got, err := tc.spec.getTargetID(podStatus); err != nil {
 | 
					 | 
				
			||||||
				t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
 | 
					 | 
				
			||||||
			} else if got != nil {
 | 
					 | 
				
			||||||
				t.Errorf("%v: getTargetID got: %v, wanted nil", t.Name(), got)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -578,7 +578,6 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Ephemeral containers may be started even if initialization is not yet complete.
 | 
						// Ephemeral containers may be started even if initialization is not yet complete.
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
	for i := range pod.Spec.EphemeralContainers {
 | 
						for i := range pod.Spec.EphemeralContainers {
 | 
				
			||||||
		c := (*v1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon)
 | 
							c := (*v1.Container)(&pod.Spec.EphemeralContainers[i].EphemeralContainerCommon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -587,7 +586,6 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku
 | 
				
			|||||||
			changes.EphemeralContainersToStart = append(changes.EphemeralContainersToStart, i)
 | 
								changes.EphemeralContainersToStart = append(changes.EphemeralContainersToStart, i)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check initialization progress.
 | 
						// Check initialization progress.
 | 
				
			||||||
	initLastStatus, next, done := findNextInitContainerToRun(pod, podStatus)
 | 
						initLastStatus, next, done := findNextInitContainerToRun(pod, podStatus)
 | 
				
			||||||
@@ -914,11 +912,9 @@ func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontaine
 | 
				
			|||||||
	// These are started "prior" to init containers to allow running ephemeral containers even when there
 | 
						// These are started "prior" to init containers to allow running ephemeral containers even when there
 | 
				
			||||||
	// are errors starting an init container. In practice init containers will start first since ephemeral
 | 
						// are errors starting an init container. In practice init containers will start first since ephemeral
 | 
				
			||||||
	// containers cannot be specified on pod creation.
 | 
						// containers cannot be specified on pod creation.
 | 
				
			||||||
	if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
	for _, idx := range podContainerChanges.EphemeralContainersToStart {
 | 
						for _, idx := range podContainerChanges.EphemeralContainersToStart {
 | 
				
			||||||
		start("ephemeral container", metrics.EphemeralContainer, ephemeralContainerStartSpec(&pod.Spec.EphemeralContainers[idx]))
 | 
							start("ephemeral container", metrics.EphemeralContainer, ephemeralContainerStartSpec(&pod.Spec.EphemeralContainers[idx]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Step 6: start the init container.
 | 
						// Step 6: start the init container.
 | 
				
			||||||
	if container := podContainerChanges.NextInitContainerToStart; container != nil {
 | 
						if container := podContainerChanges.NextInitContainerToStart; container != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,14 +35,11 @@ import (
 | 
				
			|||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/util/flowcontrol"
 | 
						"k8s.io/client-go/util/flowcontrol"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
						runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
 | 
				
			||||||
	apitest "k8s.io/cri-api/pkg/apis/testing"
 | 
						apitest "k8s.io/cri-api/pkg/apis/testing"
 | 
				
			||||||
	podutil "k8s.io/kubernetes/pkg/api/v1/pod"
 | 
						podutil "k8s.io/kubernetes/pkg/api/v1/pod"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/credentialprovider"
 | 
						"k8s.io/kubernetes/pkg/credentialprovider"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
						kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
				
			||||||
	containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
 | 
						containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
 | 
				
			||||||
	proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
 | 
						proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
 | 
				
			||||||
@@ -490,9 +487,6 @@ func TestGetPods(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestKillPod(t *testing.T) {
 | 
					func TestKillPod(t *testing.T) {
 | 
				
			||||||
	// Tests that KillPod also kills Ephemeral Containers
 | 
					 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fakeRuntime, _, m, err := createTestRuntimeManager()
 | 
						fakeRuntime, _, m, err := createTestRuntimeManager()
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1372,7 +1366,6 @@ func makeBasePodAndStatusWithInitContainers() (*v1.Pod, *kubecontainer.PodStatus
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestComputePodActionsWithInitAndEphemeralContainers(t *testing.T) {
 | 
					func TestComputePodActionsWithInitAndEphemeralContainers(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
	// Make sure existing test cases pass with feature enabled
 | 
						// Make sure existing test cases pass with feature enabled
 | 
				
			||||||
	TestComputePodActions(t)
 | 
						TestComputePodActions(t)
 | 
				
			||||||
	TestComputePodActionsWithInitContainers(t)
 | 
						TestComputePodActionsWithInitContainers(t)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,8 +22,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/configmap"
 | 
						"k8s.io/kubernetes/pkg/kubelet/configmap"
 | 
				
			||||||
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
						kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/metrics"
 | 
						"k8s.io/kubernetes/pkg/kubelet/metrics"
 | 
				
			||||||
@@ -162,10 +160,6 @@ func (pm *basicManager) UpdatePod(pod *v1.Pod) {
 | 
				
			|||||||
// updateMetrics updates the metrics surfaced by the pod manager.
 | 
					// updateMetrics updates the metrics surfaced by the pod manager.
 | 
				
			||||||
// oldPod or newPod may be nil to signify creation or deletion.
 | 
					// oldPod or newPod may be nil to signify creation or deletion.
 | 
				
			||||||
func updateMetrics(oldPod, newPod *v1.Pod) {
 | 
					func updateMetrics(oldPod, newPod *v1.Pod) {
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var numEC int
 | 
						var numEC int
 | 
				
			||||||
	if oldPod != nil {
 | 
						if oldPod != nil {
 | 
				
			||||||
		numEC -= len(oldPod.Spec.EphemeralContainers)
 | 
							numEC -= len(oldPod.Spec.EphemeralContainers)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -916,7 +916,7 @@ func (s *Server) checkpoint(request *restful.Request, response *restful.Response
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !found && utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
						if !found {
 | 
				
			||||||
		for _, container := range pod.Spec.EphemeralContainers {
 | 
							for _, container := range pod.Spec.EphemeralContainers {
 | 
				
			||||||
			if container.Name == containerName {
 | 
								if container.Name == containerName {
 | 
				
			||||||
				found = true
 | 
									found = true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,12 +33,10 @@ import (
 | 
				
			|||||||
	"k8s.io/apiserver/pkg/storage"
 | 
						"k8s.io/apiserver/pkg/storage"
 | 
				
			||||||
	storeerr "k8s.io/apiserver/pkg/storage/errors"
 | 
						storeerr "k8s.io/apiserver/pkg/storage/errors"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/util/dryrun"
 | 
						"k8s.io/apiserver/pkg/util/dryrun"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
 | 
						policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
 | 
				
			||||||
	podutil "k8s.io/kubernetes/pkg/api/pod"
 | 
						podutil "k8s.io/kubernetes/pkg/api/pod"
 | 
				
			||||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						api "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/core/validation"
 | 
						"k8s.io/kubernetes/pkg/apis/core/validation"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/client"
 | 
						"k8s.io/kubernetes/pkg/kubelet/client"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/printers"
 | 
						"k8s.io/kubernetes/pkg/printers"
 | 
				
			||||||
	printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
 | 
						printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
 | 
				
			||||||
@@ -330,10 +328,6 @@ var _ = rest.Patcher(&EphemeralContainersREST{})
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Get retrieves the object from the storage. It is required to support Patch.
 | 
					// Get retrieves the object from the storage. It is required to support Patch.
 | 
				
			||||||
func (r *EphemeralContainersREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
 | 
					func (r *EphemeralContainersREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		return nil, errors.NewBadRequest("feature EphemeralContainers disabled")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return r.store.Get(ctx, name, options)
 | 
						return r.store.Get(ctx, name, options)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -350,10 +344,6 @@ func (r *EphemeralContainersREST) Destroy() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Update alters the EphemeralContainers field in PodSpec
 | 
					// Update alters the EphemeralContainers field in PodSpec
 | 
				
			||||||
func (r *EphemeralContainersREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
 | 
					func (r *EphemeralContainersREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		return nil, false, errors.NewBadRequest("feature EphemeralContainers disabled")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
 | 
						// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
 | 
				
			||||||
	// subresources should never allow create on update.
 | 
						// subresources should never allow create on update.
 | 
				
			||||||
	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
 | 
						return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,12 +35,9 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
 | 
						genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/tools/cache"
 | 
						"k8s.io/client-go/tools/cache"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	apitesting "k8s.io/kubernetes/pkg/api/testing"
 | 
						apitesting "k8s.io/kubernetes/pkg/api/testing"
 | 
				
			||||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						api "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/client"
 | 
						"k8s.io/kubernetes/pkg/kubelet/client"
 | 
				
			||||||
	utilpointer "k8s.io/utils/pointer"
 | 
						utilpointer "k8s.io/utils/pointer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -355,7 +352,6 @@ func (g mockPodGetter) Get(context.Context, string, *metav1.GetOptions) (runtime
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCheckLogLocation(t *testing.T) {
 | 
					func TestCheckLogLocation(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
	ctx := genericapirequest.NewDefaultContext()
 | 
						ctx := genericapirequest.NewDefaultContext()
 | 
				
			||||||
	fakePodName := "test"
 | 
						fakePodName := "test"
 | 
				
			||||||
	tcs := []struct {
 | 
						tcs := []struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,13 +36,11 @@ import (
 | 
				
			|||||||
	genericapiserver "k8s.io/apiserver/pkg/server"
 | 
						genericapiserver "k8s.io/apiserver/pkg/server"
 | 
				
			||||||
	serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
						serverstorage "k8s.io/apiserver/pkg/server/storage"
 | 
				
			||||||
	"k8s.io/apiserver/pkg/storage/etcd3"
 | 
						"k8s.io/apiserver/pkg/storage/etcd3"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
 | 
						policyclient "k8s.io/client-go/kubernetes/typed/policy/v1"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
						"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
				
			||||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						api "k8s.io/kubernetes/pkg/apis/core"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/cluster/ports"
 | 
						"k8s.io/kubernetes/pkg/cluster/ports"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
 | 
						kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/registry/core/componentstatus"
 | 
						"k8s.io/kubernetes/pkg/registry/core/componentstatus"
 | 
				
			||||||
	configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage"
 | 
						configmapstore "k8s.io/kubernetes/pkg/registry/core/configmap/storage"
 | 
				
			||||||
@@ -291,9 +289,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(apiResourceConfigSource
 | 
				
			|||||||
		if podStorage.Eviction != nil {
 | 
							if podStorage.Eviction != nil {
 | 
				
			||||||
			storage[resource+"/eviction"] = podStorage.Eviction
 | 
								storage[resource+"/eviction"] = podStorage.Eviction
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
 | 
					 | 
				
			||||||
		storage[resource+"/ephemeralcontainers"] = podStorage.EphemeralContainers
 | 
							storage[resource+"/ephemeralcontainers"] = podStorage.EphemeralContainers
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if resource := "bindings"; apiResourceConfigSource.ResourceEnabled(corev1.SchemeGroupVersion.WithResource(resource)) {
 | 
						if resource := "bindings"; apiResourceConfigSource.ResourceEnabled(corev1.SchemeGroupVersion.WithResource(resource)) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,10 +28,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	_ "k8s.io/kubernetes/pkg/apis/core/install"
 | 
						_ "k8s.io/kubernetes/pkg/apis/core/install"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/slice"
 | 
						"k8s.io/kubernetes/pkg/util/slice"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/volume"
 | 
						"k8s.io/kubernetes/pkg/volume"
 | 
				
			||||||
	utilptr "k8s.io/utils/pointer"
 | 
						utilptr "k8s.io/utils/pointer"
 | 
				
			||||||
@@ -581,7 +578,6 @@ func TestMakeAbsolutePath(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetPodVolumeNames(t *testing.T) {
 | 
					func TestGetPodVolumeNames(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name            string
 | 
							name            string
 | 
				
			||||||
		pod             *v1.Pod
 | 
							pod             *v1.Pod
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,12 +20,10 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	apierrors "k8s.io/apimachinery/pkg/api/errors"
 | 
					 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/util/format"
 | 
						"k8s.io/kubernetes/pkg/kubelet/util/format"
 | 
				
			||||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
						"k8s.io/kubernetes/test/e2e/framework"
 | 
				
			||||||
	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
 | 
						e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
 | 
				
			||||||
	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
 | 
					 | 
				
			||||||
	imageutils "k8s.io/kubernetes/test/utils/image"
 | 
						imageutils "k8s.io/kubernetes/test/utils/image"
 | 
				
			||||||
	admissionapi "k8s.io/pod-security-admission/api"
 | 
						admissionapi "k8s.io/pod-security-admission/api"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,11 +67,6 @@ var _ = SIGDescribe("Ephemeral Containers [NodeConformance]", func() {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		err := podClient.AddEphemeralContainerSync(pod, ec, time.Minute)
 | 
							err := podClient.AddEphemeralContainerSync(pod, ec, time.Minute)
 | 
				
			||||||
		// BEGIN TODO: Remove when EphemeralContainers feature gate is retired.
 | 
					 | 
				
			||||||
		if apierrors.IsNotFound(err) {
 | 
					 | 
				
			||||||
			e2eskipper.Skipf("Skipping test because EphemeralContainers feature disabled (error: %q)", err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// END TODO: Remove when EphemeralContainers feature gate is retired.
 | 
					 | 
				
			||||||
		framework.ExpectNoError(err, "Failed to patch ephemeral containers in pod %q", format.Pod(pod))
 | 
							framework.ExpectNoError(err, "Failed to patch ephemeral containers in pod %q", format.Pod(pod))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ginkgo.By("checking pod container endpoints")
 | 
							ginkgo.By("checking pod container endpoints")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,6 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/util/uuid"
 | 
						"k8s.io/apimachinery/pkg/util/uuid"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						"k8s.io/apimachinery/pkg/util/wait"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/watch"
 | 
						"k8s.io/apimachinery/pkg/watch"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	"k8s.io/client-go/dynamic"
 | 
						"k8s.io/client-go/dynamic"
 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
	restclient "k8s.io/client-go/rest"
 | 
						restclient "k8s.io/client-go/rest"
 | 
				
			||||||
@@ -58,7 +57,6 @@ import (
 | 
				
			|||||||
	"k8s.io/client-go/tools/clientcmd"
 | 
						"k8s.io/client-go/tools/clientcmd"
 | 
				
			||||||
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
						clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
 | 
				
			||||||
	watchtools "k8s.io/client-go/tools/watch"
 | 
						watchtools "k8s.io/client-go/tools/watch"
 | 
				
			||||||
	"k8s.io/component-base/featuregate"
 | 
					 | 
				
			||||||
	testutils "k8s.io/kubernetes/test/utils"
 | 
						testutils "k8s.io/kubernetes/test/utils"
 | 
				
			||||||
	imageutils "k8s.io/kubernetes/test/utils/image"
 | 
						imageutils "k8s.io/kubernetes/test/utils/image"
 | 
				
			||||||
	uexec "k8s.io/utils/exec"
 | 
						uexec "k8s.io/utils/exec"
 | 
				
			||||||
@@ -776,8 +774,6 @@ func (f *Framework) testContainerOutputMatcher(scenarioName string,
 | 
				
			|||||||
type ContainerType int
 | 
					type ContainerType int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	// FeatureEphemeralContainers allows running an ephemeral container in pod namespaces to troubleshoot a running pod
 | 
					 | 
				
			||||||
	FeatureEphemeralContainers featuregate.Feature = "EphemeralContainers"
 | 
					 | 
				
			||||||
	// Containers is for normal containers
 | 
						// Containers is for normal containers
 | 
				
			||||||
	Containers ContainerType = 1 << iota
 | 
						Containers ContainerType = 1 << iota
 | 
				
			||||||
	// InitContainers is for init containers
 | 
						// InitContainers is for init containers
 | 
				
			||||||
@@ -790,11 +786,7 @@ const (
 | 
				
			|||||||
// types except for the ones guarded by feature gate.
 | 
					// types except for the ones guarded by feature gate.
 | 
				
			||||||
// Copied from pkg/api/v1/pod to avoid pulling extra dependencies
 | 
					// Copied from pkg/api/v1/pod to avoid pulling extra dependencies
 | 
				
			||||||
func allFeatureEnabledContainers() ContainerType {
 | 
					func allFeatureEnabledContainers() ContainerType {
 | 
				
			||||||
	containerType := AllContainers
 | 
						return AllContainers
 | 
				
			||||||
	if !utilfeature.DefaultFeatureGate.Enabled(FeatureEphemeralContainers) {
 | 
					 | 
				
			||||||
		containerType &= ^EphemeralContainers
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return containerType
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContainerVisitor is called with each container spec, and returns true
 | 
					// ContainerVisitor is called with each container spec, and returns true
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -609,12 +609,6 @@ func testVolumeClient(f *framework.Framework, config TestConfig, fsGroup *int64,
 | 
				
			|||||||
	ec.Name = "volume-ephemeral-container"
 | 
						ec.Name = "volume-ephemeral-container"
 | 
				
			||||||
	err = f.PodClient().AddEphemeralContainerSync(clientPod, ec, timeouts.PodStart)
 | 
						err = f.PodClient().AddEphemeralContainerSync(clientPod, ec, timeouts.PodStart)
 | 
				
			||||||
	// The API server will return NotFound for the subresource when the feature is disabled
 | 
						// The API server will return NotFound for the subresource when the feature is disabled
 | 
				
			||||||
	// BEGIN TODO: remove after EphemeralContainers feature gate is retired
 | 
					 | 
				
			||||||
	if apierrors.IsNotFound(err) {
 | 
					 | 
				
			||||||
		framework.Logf("Skipping ephemeral container re-test because feature is disabled (error: %q)", err)
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// END TODO: remove after EphemeralContainers feature gate is retired
 | 
					 | 
				
			||||||
	framework.ExpectNoError(err, "failed to add ephemeral container for re-test")
 | 
						framework.ExpectNoError(err, "failed to add ephemeral container for re-test")
 | 
				
			||||||
	testVolumeContent(f, clientPod, ec.Name, fsGroup, fsType, tests)
 | 
						testVolumeContent(f, clientPod, ec.Name, fsGroup, fsType, tests)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -491,7 +491,7 @@ func testWebhookAdmission(t *testing.T, watchCache bool) {
 | 
				
			|||||||
		// force enable all resources so we can check storage.
 | 
							// force enable all resources so we can check storage.
 | 
				
			||||||
		"--runtime-config=api/all=true",
 | 
							"--runtime-config=api/all=true",
 | 
				
			||||||
		// enable feature-gates that protect resources to check their storage, too.
 | 
							// enable feature-gates that protect resources to check their storage, too.
 | 
				
			||||||
		"--feature-gates=EphemeralContainers=true",
 | 
							// e.g. "--feature-gates=EphemeralContainers=true",
 | 
				
			||||||
	}, etcdConfig)
 | 
						}, etcdConfig)
 | 
				
			||||||
	defer server.TearDownFn()
 | 
						defer server.TearDownFn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,15 +23,11 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v1 "k8s.io/api/core/v1"
 | 
						v1 "k8s.io/api/core/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
					 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	utilfeature "k8s.io/apiserver/pkg/util/feature"
 | 
					 | 
				
			||||||
	clientset "k8s.io/client-go/kubernetes"
 | 
						clientset "k8s.io/client-go/kubernetes"
 | 
				
			||||||
	typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
						typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
 | 
				
			||||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
					 | 
				
			||||||
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
						kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/features"
 | 
					 | 
				
			||||||
	"k8s.io/kubernetes/test/integration"
 | 
						"k8s.io/kubernetes/test/integration"
 | 
				
			||||||
	"k8s.io/kubernetes/test/integration/framework"
 | 
						"k8s.io/kubernetes/test/integration/framework"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -190,8 +186,6 @@ func TestPodReadOnlyFilesystem(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodCreateEphemeralContainers(t *testing.T) {
 | 
					func TestPodCreateEphemeralContainers(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
						// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
				
			||||||
	defer server.TearDownFn()
 | 
						defer server.TearDownFn()
 | 
				
			||||||
@@ -261,8 +255,6 @@ func setUpEphemeralContainers(podsClient typedv1.PodInterface, pod *v1.Pod, cont
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodPatchEphemeralContainers(t *testing.T) {
 | 
					func TestPodPatchEphemeralContainers(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
						// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
				
			||||||
	defer server.TearDownFn()
 | 
						defer server.TearDownFn()
 | 
				
			||||||
@@ -494,8 +486,6 @@ func TestPodPatchEphemeralContainers(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPodUpdateEphemeralContainers(t *testing.T) {
 | 
					func TestPodUpdateEphemeralContainers(t *testing.T) {
 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
						// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
						server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
				
			||||||
	defer server.TearDownFn()
 | 
						defer server.TearDownFn()
 | 
				
			||||||
@@ -684,61 +674,3 @@ func TestPodUpdateEphemeralContainers(t *testing.T) {
 | 
				
			|||||||
		integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
 | 
							integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// TestPodEphemeralContainersDisabled tests that the API server returns a 404 when the feature is disabled (because the subresource won't exist).
 | 
					 | 
				
			||||||
// This validates that the feature gate is working, but kubectl also uses the 404 to guess that the feature is disabled on the server.
 | 
					 | 
				
			||||||
func TestPodEphemeralContainersDisabled(t *testing.T) {
 | 
					 | 
				
			||||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, false)()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 | 
					 | 
				
			||||||
	server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
 | 
					 | 
				
			||||||
	defer server.TearDownFn()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client := clientset.NewForConfigOrDie(server.ClientConfig)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ns := framework.CreateNamespaceOrDie(client, "pod-ephemeral-containers-disabled", t)
 | 
					 | 
				
			||||||
	defer framework.DeleteNamespaceOrDie(client, ns, t)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pod := &v1.Pod{
 | 
					 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{
 | 
					 | 
				
			||||||
			Name: "ephemeral-container-pod",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Spec: v1.PodSpec{
 | 
					 | 
				
			||||||
			Containers: []v1.Container{
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					Name:  "fake-name",
 | 
					 | 
				
			||||||
					Image: "fakeimage",
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pod, err := setUpEphemeralContainers(client.CoreV1().Pods(ns.Name), pod, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pod.Spec.EphemeralContainers = append(pod.Spec.EphemeralContainers, v1.EphemeralContainer{
 | 
					 | 
				
			||||||
		EphemeralContainerCommon: v1.EphemeralContainerCommon{
 | 
					 | 
				
			||||||
			Name:                     "debugger",
 | 
					 | 
				
			||||||
			Image:                    "debugimage",
 | 
					 | 
				
			||||||
			ImagePullPolicy:          "Always",
 | 
					 | 
				
			||||||
			TerminationMessagePolicy: "File",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if _, err = client.CoreV1().Pods(ns.Name).UpdateEphemeralContainers(context.TODO(), pod.Name, pod, metav1.UpdateOptions{}); err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("got nil error when updating ephemeral containers with feature disabled, wanted %q", metav1.StatusReasonNotFound)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	se, ok := err.(*errors.StatusError)
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		t.Fatalf("got error %#v, expected StatusError", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if se.ErrStatus.Reason != metav1.StatusReasonNotFound {
 | 
					 | 
				
			||||||
		t.Errorf("got error reason %q when updating ephemeral containers with feature disabled, want %q: %#v", se.ErrStatus.Reason, metav1.StatusReasonNotFound, se)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if se.ErrStatus.Details.Name != "" {
 | 
					 | 
				
			||||||
		t.Errorf("got error details with name %q, want %q: %#v", se.ErrStatus.Details.Name, "", se)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user