mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Remove EphemeralContainers feature-gate checks
This commit is contained in:
parent
bc3c5ae269
commit
d238e67ba6
@ -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 {
|
||||||
|
@ -39,11 +39,10 @@ import (
|
|||||||
func TestVisitContainers(t *testing.T) {
|
func TestVisitContainers(t *testing.T) {
|
||||||
setAllFeatureEnabledContainersDuringTest := ContainerType(0)
|
setAllFeatureEnabledContainersDuringTest := ContainerType(0)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
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{
|
||||||
@ -162,9 +142,8 @@ func TestVisitContainers(t *testing.T) {
|
|||||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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) {
|
||||||
@ -205,11 +202,10 @@ func TestFindPort(t *testing.T) {
|
|||||||
func TestVisitContainers(t *testing.T) {
|
func TestVisitContainers(t *testing.T) {
|
||||||
setAllFeatureEnabledContainersDuringTest := ContainerType(0)
|
setAllFeatureEnabledContainersDuringTest := ContainerType(0)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
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"},
|
||||||
@ -328,9 +305,8 @@ func TestVisitContainers(t *testing.T) {
|
|||||||
{EphemeralContainerCommon: v1.EphemeralContainerCommon{Name: "e2"}},
|
{EphemeralContainerCommon: v1.EphemeralContainerCommon{Name: "e2"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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,12 +45,10 @@ 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,15 +65,13 @@ 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 {
|
if here.Name == "" {
|
||||||
if here.Name == "" {
|
return fmt.Sprintf("spec.ephemeralContainers[%d]", i), nil
|
||||||
return fmt.Sprintf("spec.ephemeralContainers[%d]", i), nil
|
|
||||||
}
|
|
||||||
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,23 +1602,21 @@ 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))
|
|
||||||
}
|
|
||||||
|
|
||||||
// #80875: By now we've iterated podStatus 3 times. We could refactor this to make a single
|
|
||||||
// pass through podStatus.ContainerStatuses
|
|
||||||
apiPodStatus.EphemeralContainerStatuses = kl.convertToAPIContainerStatuses(
|
|
||||||
pod, podStatus,
|
|
||||||
oldPodStatus.EphemeralContainerStatuses,
|
|
||||||
ecSpecs,
|
|
||||||
len(pod.Spec.InitContainers) > 0,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #80875: By now we've iterated podStatus 3 times. We could refactor this to make a single
|
||||||
|
// pass through podStatus.ContainerStatuses
|
||||||
|
apiPodStatus.EphemeralContainerStatuses = kl.convertToAPIContainerStatuses(
|
||||||
|
pod, podStatus,
|
||||||
|
oldPodStatus.EphemeralContainerStatuses,
|
||||||
|
ecSpecs,
|
||||||
|
len(pod.Spec.InitContainers) > 0,
|
||||||
|
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,14 +578,12 @@ 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)
|
|
||||||
|
|
||||||
// Ephemeral Containers are never restarted
|
// Ephemeral Containers are never restarted
|
||||||
if podStatus.FindContainerStatusByName(c.Name) == nil {
|
if podStatus.FindContainerStatusByName(c.Name) == nil {
|
||||||
changes.EphemeralContainersToStart = append(changes.EphemeralContainersToStart, i)
|
changes.EphemeralContainersToStart = append(changes.EphemeralContainersToStart, i)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,10 +912,8 @@ 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.
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user