mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-08-08 15:25:26 +00:00
Merge pull request #131463 from gjkim42/remove-legacysidecarcontainers-fg
Remove deprecated LegacySidecarContainers feature gate
This commit is contained in:
@@ -498,14 +498,6 @@ const (
|
||||
// Add support for distributed tracing in the kubelet
|
||||
KubeletTracing featuregate.Feature = "KubeletTracing"
|
||||
|
||||
// owner: @gjkim42
|
||||
//
|
||||
// Enable legacy code path in pkg/kubelet/kuberuntime that predates the
|
||||
// SidecarContainers feature. This temporary feature gate is disabled by
|
||||
// default and intended to safely remove the redundant code path. This is
|
||||
// only available in v1.33 and will be removed in v1.34.
|
||||
LegacySidecarContainers featuregate.Feature = "LegacySidecarContainers"
|
||||
|
||||
// owner: @Sh4d1,@RyanAoh,@rikatz
|
||||
// kep: http://kep.k8s.io/1860
|
||||
// LoadBalancerIPMode enables the IPMode field in the LoadBalancerIngress status of a Service
|
||||
@@ -1350,11 +1342,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
|
||||
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.37
|
||||
},
|
||||
|
||||
LegacySidecarContainers: {
|
||||
{Version: version.MustParse("1.0"), Default: true, PreRelease: featuregate.GA},
|
||||
{Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Deprecated},
|
||||
},
|
||||
|
||||
LoadBalancerIPMode: {
|
||||
{Version: version.MustParse("1.29"), Default: false, PreRelease: featuregate.Alpha},
|
||||
{Version: version.MustParse("1.30"), Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
@@ -974,65 +974,6 @@ func (m *kubeGenericRuntimeManager) purgeInitContainers(ctx context.Context, pod
|
||||
}
|
||||
}
|
||||
|
||||
// findNextInitContainerToRun returns the status of the last failed container, the
|
||||
// index of next init container to start, or done if there are no further init containers.
|
||||
// Status is only returned if an init container is failed, in which case next will
|
||||
// point to the current container.
|
||||
// TODO: Remove this function as this is a subset of the
|
||||
// computeInitContainerActions.
|
||||
func findNextInitContainerToRun(pod *v1.Pod, podStatus *kubecontainer.PodStatus) (status *kubecontainer.Status, next *v1.Container, done bool) {
|
||||
if len(pod.Spec.InitContainers) == 0 {
|
||||
return nil, nil, true
|
||||
}
|
||||
|
||||
// If any of the main containers have status and are Running, then all init containers must
|
||||
// have been executed at some point in the past. However, they could have been removed
|
||||
// from the container runtime now, and if we proceed, it would appear as if they
|
||||
// never ran and will re-execute improperly.
|
||||
for i := range pod.Spec.Containers {
|
||||
container := &pod.Spec.Containers[i]
|
||||
status := podStatus.FindContainerStatusByName(container.Name)
|
||||
if status != nil && status.State == kubecontainer.ContainerStateRunning {
|
||||
return nil, nil, true
|
||||
}
|
||||
}
|
||||
|
||||
// If there are failed containers, return the status of the last failed one.
|
||||
for i := len(pod.Spec.InitContainers) - 1; i >= 0; i-- {
|
||||
container := &pod.Spec.InitContainers[i]
|
||||
status := podStatus.FindContainerStatusByName(container.Name)
|
||||
if status != nil && isInitContainerFailed(status) {
|
||||
return status, container, false
|
||||
}
|
||||
}
|
||||
|
||||
// There are no failed containers now.
|
||||
for i := len(pod.Spec.InitContainers) - 1; i >= 0; i-- {
|
||||
container := &pod.Spec.InitContainers[i]
|
||||
status := podStatus.FindContainerStatusByName(container.Name)
|
||||
if status == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// container is still running, return not done.
|
||||
if status.State == kubecontainer.ContainerStateRunning {
|
||||
return nil, nil, false
|
||||
}
|
||||
|
||||
if status.State == kubecontainer.ContainerStateExited {
|
||||
// all init containers successful
|
||||
if i == (len(pod.Spec.InitContainers) - 1) {
|
||||
return nil, nil, true
|
||||
}
|
||||
|
||||
// all containers up to i successful, go to i+1
|
||||
return nil, &pod.Spec.InitContainers[i+1], false
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &pod.Spec.InitContainers[0], false
|
||||
}
|
||||
|
||||
// hasAnyRegularContainerCreated returns true if any regular container has been
|
||||
// created, which indicates all init containers have been initialized.
|
||||
func hasAnyRegularContainerCreated(pod *v1.Pod, podStatus *kubecontainer.PodStatus) bool {
|
||||
@@ -1062,10 +1003,6 @@ func hasAnyRegularContainerCreated(pod *v1.Pod, podStatus *kubecontainer.PodStat
|
||||
// - Start the first init container that has not been started.
|
||||
// - Restart all restartable init containers that have started but are not running.
|
||||
// - Kill the restartable init containers that are not alive or started.
|
||||
//
|
||||
// Note that this is a function for the SidecarContainers feature.
|
||||
// Please sync with the findNextInitContainerToRun function if any changes are
|
||||
// made, as either this or that function will be called.
|
||||
func (m *kubeGenericRuntimeManager) computeInitContainerActions(pod *v1.Pod, podStatus *kubecontainer.PodStatus, changes *podActions) bool {
|
||||
if len(pod.Spec.InitContainers) == 0 {
|
||||
return true
|
||||
|
||||
@@ -533,15 +533,9 @@ type podActions struct {
|
||||
// The attempt number of creating sandboxes for the pod.
|
||||
Attempt uint32
|
||||
|
||||
// The next init container to start.
|
||||
// TODO: Either this or InitContainersToStart will be used. Remove this
|
||||
// field once it is not needed.
|
||||
NextInitContainerToStart *v1.Container
|
||||
// InitContainersToStart keeps a list of indexes for the init containers to
|
||||
// start, where the index is the index of the specific init container in the
|
||||
// pod spec (pod.Spec.InitContainers).
|
||||
// NOTE: This is a field for SidecarContainers feature. Either this or
|
||||
// NextInitContainerToStart will be set.
|
||||
InitContainersToStart []int
|
||||
// ContainersToStart keeps a list of indexes for the containers to start,
|
||||
// where the index is the index of the specific container in the pod spec (
|
||||
@@ -991,10 +985,6 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
|
||||
ContainersToKill: make(map[kubecontainer.ContainerID]containerToKillInfo),
|
||||
}
|
||||
|
||||
// TODO: Remove handleRestartableInitContainers value with the
|
||||
// LegacySidecarContainers feature gate.
|
||||
handleRestartableInitContainers := types.HasRestartableInitContainer(pod) || !utilfeature.DefaultFeatureGate.Enabled(features.LegacySidecarContainers)
|
||||
|
||||
// If we need to (re-)create the pod sandbox, everything will need to be
|
||||
// killed and recreated, and init containers should be purged.
|
||||
if createPodSandbox {
|
||||
@@ -1024,15 +1014,10 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
|
||||
// is done and there is no container to start.
|
||||
if len(containersToStart) == 0 {
|
||||
hasInitialized := false
|
||||
// TODO: Remove this code path as logically it is the subset of the next
|
||||
// code path.
|
||||
if !handleRestartableInitContainers {
|
||||
_, _, hasInitialized = findNextInitContainerToRun(pod, podStatus)
|
||||
} else {
|
||||
// If there is any regular container, it means all init containers have
|
||||
// been initialized.
|
||||
hasInitialized = hasAnyRegularContainerCreated(pod, podStatus)
|
||||
}
|
||||
|
||||
// If there is any regular container, it means all init containers have
|
||||
// been initialized.
|
||||
hasInitialized = hasAnyRegularContainerCreated(pod, podStatus)
|
||||
|
||||
if hasInitialized {
|
||||
changes.CreateSandbox = false
|
||||
@@ -1044,13 +1029,7 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
|
||||
// state.
|
||||
if len(pod.Spec.InitContainers) != 0 {
|
||||
// Pod has init containers, return the first one.
|
||||
// TODO: Remove this code path as logically it is the subset of the next
|
||||
// code path.
|
||||
if !handleRestartableInitContainers {
|
||||
changes.NextInitContainerToStart = &pod.Spec.InitContainers[0]
|
||||
} else {
|
||||
changes.InitContainersToStart = []int{0}
|
||||
}
|
||||
changes.InitContainersToStart = []int{0}
|
||||
|
||||
return changes
|
||||
}
|
||||
@@ -1073,40 +1052,11 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
|
||||
}
|
||||
|
||||
// Check initialization progress.
|
||||
// TODO: Remove this code path as logically it is the subset of the next
|
||||
// code path.
|
||||
if !handleRestartableInitContainers {
|
||||
initLastStatus, next, done := findNextInitContainerToRun(pod, podStatus)
|
||||
if !done {
|
||||
if next != nil {
|
||||
initFailed := initLastStatus != nil && isInitContainerFailed(initLastStatus)
|
||||
if initFailed && !shouldRestartOnFailure(pod) {
|
||||
changes.KillPod = true
|
||||
} else {
|
||||
// Always try to stop containers in unknown state first.
|
||||
if initLastStatus != nil && initLastStatus.State == kubecontainer.ContainerStateUnknown {
|
||||
changes.ContainersToKill[initLastStatus.ID] = containerToKillInfo{
|
||||
name: next.Name,
|
||||
container: next,
|
||||
message: fmt.Sprintf("Init container is in %q state, try killing it before restart",
|
||||
initLastStatus.State),
|
||||
reason: reasonUnknown,
|
||||
}
|
||||
}
|
||||
changes.NextInitContainerToStart = next
|
||||
}
|
||||
}
|
||||
// Initialization failed or still in progress. Skip inspecting non-init
|
||||
// containers.
|
||||
return changes
|
||||
}
|
||||
} else {
|
||||
hasInitialized := m.computeInitContainerActions(pod, podStatus, &changes)
|
||||
if changes.KillPod || !hasInitialized {
|
||||
// Initialization failed or still in progress. Skip inspecting non-init
|
||||
// containers.
|
||||
return changes
|
||||
}
|
||||
hasInitialized := m.computeInitContainerActions(pod, podStatus, &changes)
|
||||
if changes.KillPod || !hasInitialized {
|
||||
// Initialization failed or still in progress. Skip inspecting non-init
|
||||
// containers.
|
||||
return changes
|
||||
}
|
||||
|
||||
// Number of running containers to keep.
|
||||
@@ -1191,13 +1141,9 @@ func (m *kubeGenericRuntimeManager) computePodActions(ctx context.Context, pod *
|
||||
|
||||
if keepCount == 0 && len(changes.ContainersToStart) == 0 {
|
||||
changes.KillPod = true
|
||||
// TODO: Remove this code path as logically it is the subset of the next
|
||||
// code path.
|
||||
if handleRestartableInitContainers {
|
||||
// To prevent the restartable init containers to keep pod alive, we should
|
||||
// not restart them.
|
||||
changes.InitContainersToStart = nil
|
||||
}
|
||||
// To prevent the restartable init containers to keep pod alive, we should
|
||||
// not restart them.
|
||||
changes.InitContainersToStart = nil
|
||||
}
|
||||
|
||||
return changes
|
||||
@@ -1453,36 +1399,21 @@ func (m *kubeGenericRuntimeManager) SyncPod(ctx context.Context, pod *v1.Pod, po
|
||||
start(ctx, "ephemeral container", metrics.EphemeralContainer, ephemeralContainerStartSpec(&pod.Spec.EphemeralContainers[idx]))
|
||||
}
|
||||
|
||||
// TODO: Remove this code path as logically it is the subset of the next
|
||||
// code path.
|
||||
if !types.HasRestartableInitContainer(pod) && utilfeature.DefaultFeatureGate.Enabled(features.LegacySidecarContainers) {
|
||||
// Step 6: start the init container.
|
||||
if container := podContainerChanges.NextInitContainerToStart; container != nil {
|
||||
// Start the next init container.
|
||||
if err := start(ctx, "init container", metrics.InitContainer, containerStartSpec(container)); err != nil {
|
||||
return
|
||||
// Step 6: start init containers.
|
||||
for _, idx := range podContainerChanges.InitContainersToStart {
|
||||
container := &pod.Spec.InitContainers[idx]
|
||||
// Start the next init container.
|
||||
if err := start(ctx, "init container", metrics.InitContainer, containerStartSpec(container)); err != nil {
|
||||
if podutil.IsRestartableInitContainer(container) {
|
||||
klog.V(4).InfoS("Failed to start the restartable init container for the pod, skipping", "initContainerName", container.Name, "pod", klog.KObj(pod))
|
||||
continue
|
||||
}
|
||||
|
||||
// Successfully started the container; clear the entry in the failure
|
||||
klog.V(4).InfoS("Completed init container for pod", "containerName", container.Name, "pod", klog.KObj(pod))
|
||||
klog.V(4).InfoS("Failed to initialize the pod, as the init container failed to start, aborting", "initContainerName", container.Name, "pod", klog.KObj(pod))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Step 6: start init containers.
|
||||
for _, idx := range podContainerChanges.InitContainersToStart {
|
||||
container := &pod.Spec.InitContainers[idx]
|
||||
// Start the next init container.
|
||||
if err := start(ctx, "init container", metrics.InitContainer, containerStartSpec(container)); err != nil {
|
||||
if podutil.IsRestartableInitContainer(container) {
|
||||
klog.V(4).InfoS("Failed to start the restartable init container for the pod, skipping", "initContainerName", container.Name, "pod", klog.KObj(pod))
|
||||
continue
|
||||
}
|
||||
klog.V(4).InfoS("Failed to initialize the pod, as the init container failed to start, aborting", "initContainerName", container.Name, "pod", klog.KObj(pod))
|
||||
return
|
||||
}
|
||||
|
||||
// Successfully started the container; clear the entry in the failure
|
||||
klog.V(4).InfoS("Completed init container for pod", "containerName", container.Name, "pod", klog.KObj(pod))
|
||||
}
|
||||
// Successfully started the container; clear the entry in the failure
|
||||
klog.V(4).InfoS("Completed init container for pod", "containerName", container.Name, "pod", klog.KObj(pod))
|
||||
}
|
||||
|
||||
// Step 7: For containers in podContainerChanges.ContainersToUpdate[CPU,Memory] list, invoke UpdateContainerResources
|
||||
|
||||
@@ -59,7 +59,6 @@ import (
|
||||
imagetypes "k8s.io/kubernetes/pkg/kubelet/images"
|
||||
"k8s.io/kubernetes/pkg/kubelet/metrics"
|
||||
proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
|
||||
kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
@@ -1498,246 +1497,6 @@ func TestComputePodActionsWithInitContainers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputePodActionsWithInitContainersWithLegacySidecarContainers(t *testing.T) {
|
||||
_, _, m, err := createTestRuntimeManager()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Creating a pair reference pod and status for the test cases to refer
|
||||
// the specific fields.
|
||||
basePod, baseStatus := makeBasePodAndStatusWithInitContainers()
|
||||
noAction := podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
}
|
||||
|
||||
for desc, test := range map[string]struct {
|
||||
mutatePodFn func(*v1.Pod)
|
||||
mutateStatusFn func(*kubecontainer.PodStatus)
|
||||
actions podActions
|
||||
}{
|
||||
"initialization completed; start all containers": {
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{0, 1, 2},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"no init containers have been started; start the first one": {
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses = nil
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"initialization in progress; do nothing": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateRunning
|
||||
},
|
||||
actions: noAction,
|
||||
},
|
||||
"Kill pod and restart the first init container if the pod sandbox is dead": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"initialization failed; restart the last init container if RestartPolicy == Always": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].ExitCode = 137
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[2],
|
||||
InitContainersToStart: []int{2},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"initialization failed; restart the last init container if RestartPolicy == OnFailure": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].ExitCode = 137
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[2],
|
||||
InitContainersToStart: []int{2},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"initialization failed; kill pod if RestartPolicy == Never": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].ExitCode = 137
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"init container state unknown; kill and recreate the last init container if RestartPolicy == Always": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateUnknown
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[2],
|
||||
InitContainersToStart: []int{2},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{2}),
|
||||
},
|
||||
},
|
||||
"init container state unknown; kill and recreate the last init container if RestartPolicy == OnFailure": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateUnknown
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[2],
|
||||
InitContainersToStart: []int{2},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{2}),
|
||||
},
|
||||
},
|
||||
"init container state unknown; kill pod if RestartPolicy == Never": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateUnknown
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"Pod sandbox not ready, init container failed, but RestartPolicy == Never; kill pod only": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: false,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"Pod sandbox not ready, and RestartPolicy == Never, but no visible init containers; create a new pod sandbox": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
status.ContainerStatuses = []*kubecontainer.Status{}
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"Pod sandbox not ready, init container failed, and RestartPolicy == OnFailure; create a new pod sandbox": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
status.ContainerStatuses[2].ExitCode = 137
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"some of the init container statuses are missing but the last init container is running, don't restart preceding ones": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateRunning
|
||||
status.ContainerStatuses = status.ContainerStatuses[2:]
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: false,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"an init container is in the created state due to an unknown error when starting container; restart it": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[2].State = kubecontainer.ContainerStateCreated
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: false,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[2],
|
||||
InitContainersToStart: []int{2},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LegacySidecarContainers, true)
|
||||
pod, status := makeBasePodAndStatusWithInitContainers()
|
||||
if test.mutatePodFn != nil {
|
||||
test.mutatePodFn(pod)
|
||||
}
|
||||
if test.mutateStatusFn != nil {
|
||||
test.mutateStatusFn(status)
|
||||
}
|
||||
ctx := context.Background()
|
||||
actions := m.computePodActions(ctx, pod, status)
|
||||
handleRestartableInitContainers := kubelettypes.HasRestartableInitContainer(pod)
|
||||
if !handleRestartableInitContainers {
|
||||
// If sidecar containers are disabled or the pod does not have any
|
||||
// restartable init container, we should not see any
|
||||
// InitContainersToStart in the actions.
|
||||
test.actions.InitContainersToStart = nil
|
||||
} else {
|
||||
// If sidecar containers are enabled and the pod has any
|
||||
// restartable init container, we should not see any
|
||||
// NextInitContainerToStart in the actions.
|
||||
test.actions.NextInitContainerToStart = nil
|
||||
}
|
||||
verifyActions(t, &test.actions, &actions, desc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeBasePodAndStatusWithInitContainers() (*v1.Pod, *kubecontainer.PodStatus) {
|
||||
pod, status := makeBasePodAndStatus()
|
||||
pod.Spec.InitContainers = []v1.Container{
|
||||
@@ -2338,168 +2097,6 @@ func TestComputePodActionsWithInitAndEphemeralContainers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputePodActionsWithInitAndEphemeralContainersWithLegacySidecarContainers(t *testing.T) {
|
||||
// Make sure existing test cases pass with feature enabled
|
||||
TestComputePodActions(t)
|
||||
TestComputePodActionsWithInitContainersWithLegacySidecarContainers(t)
|
||||
|
||||
_, _, m, err := createTestRuntimeManager()
|
||||
require.NoError(t, err)
|
||||
|
||||
basePod, baseStatus := makeBasePodAndStatusWithInitAndEphemeralContainers()
|
||||
noAction := podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
}
|
||||
|
||||
for desc, test := range map[string]struct {
|
||||
mutatePodFn func(*v1.Pod)
|
||||
mutateStatusFn func(*kubecontainer.PodStatus)
|
||||
actions podActions
|
||||
}{
|
||||
"steady state; do nothing; ignore ephemeral container": {
|
||||
actions: noAction,
|
||||
},
|
||||
"No ephemeral containers running; start one": {
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses = status.ContainerStatuses[:4]
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
EphemeralContainersToStart: []int{0},
|
||||
},
|
||||
},
|
||||
"Start second ephemeral container": {
|
||||
mutatePodFn: func(pod *v1.Pod) {
|
||||
pod.Spec.EphemeralContainers = append(pod.Spec.EphemeralContainers, v1.EphemeralContainer{
|
||||
EphemeralContainerCommon: v1.EphemeralContainerCommon{
|
||||
Name: "debug2",
|
||||
Image: "busybox",
|
||||
},
|
||||
})
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
EphemeralContainersToStart: []int{1},
|
||||
},
|
||||
},
|
||||
"Ephemeral container exited; do not restart": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[4].State = kubecontainer.ContainerStateExited
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
},
|
||||
},
|
||||
"initialization in progress; start ephemeral container": {
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[3].State = kubecontainer.ContainerStateRunning
|
||||
status.ContainerStatuses = status.ContainerStatuses[:4]
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
EphemeralContainersToStart: []int{0},
|
||||
},
|
||||
},
|
||||
"Create a new pod sandbox if the pod sandbox is dead, init container failed and RestartPolicy == OnFailure": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyOnFailure },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
status.ContainerStatuses = status.ContainerStatuses[3:]
|
||||
status.ContainerStatuses[0].ExitCode = 137
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"Kill pod and do not restart ephemeral container if the pod sandbox is dead": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyAlways },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.SandboxStatuses[0].State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||
},
|
||||
actions: podActions{
|
||||
KillPod: true,
|
||||
CreateSandbox: true,
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
Attempt: uint32(1),
|
||||
NextInitContainerToStart: &basePod.Spec.InitContainers[0],
|
||||
InitContainersToStart: []int{0},
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: getKillMapWithInitContainers(basePod, baseStatus, []int{}),
|
||||
},
|
||||
},
|
||||
"Kill pod if all containers exited except ephemeral container": {
|
||||
mutatePodFn: func(pod *v1.Pod) {
|
||||
pod.Spec.RestartPolicy = v1.RestartPolicyNever
|
||||
},
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
// all regular containers exited
|
||||
for i := 0; i < 3; i++ {
|
||||
status.ContainerStatuses[i].State = kubecontainer.ContainerStateExited
|
||||
status.ContainerStatuses[i].ExitCode = 0
|
||||
}
|
||||
},
|
||||
actions: podActions{
|
||||
SandboxID: baseStatus.SandboxStatuses[0].Id,
|
||||
CreateSandbox: false,
|
||||
KillPod: true,
|
||||
ContainersToStart: []int{},
|
||||
ContainersToKill: map[kubecontainer.ContainerID]containerToKillInfo{},
|
||||
},
|
||||
},
|
||||
"Ephemeral container is in unknown state; leave it alone": {
|
||||
mutatePodFn: func(pod *v1.Pod) { pod.Spec.RestartPolicy = v1.RestartPolicyNever },
|
||||
mutateStatusFn: func(status *kubecontainer.PodStatus) {
|
||||
status.ContainerStatuses[4].State = kubecontainer.ContainerStateUnknown
|
||||
},
|
||||
actions: noAction,
|
||||
},
|
||||
} {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LegacySidecarContainers, true)
|
||||
pod, status := makeBasePodAndStatusWithInitAndEphemeralContainers()
|
||||
if test.mutatePodFn != nil {
|
||||
test.mutatePodFn(pod)
|
||||
}
|
||||
if test.mutateStatusFn != nil {
|
||||
test.mutateStatusFn(status)
|
||||
}
|
||||
ctx := context.Background()
|
||||
actions := m.computePodActions(ctx, pod, status)
|
||||
handleRestartableInitContainers := kubelettypes.HasRestartableInitContainer(pod)
|
||||
if !handleRestartableInitContainers {
|
||||
// If sidecar containers are disabled or the pod does not have any
|
||||
// restartable init container, we should not see any
|
||||
// InitContainersToStart in the actions.
|
||||
test.actions.InitContainersToStart = nil
|
||||
} else {
|
||||
// If sidecar containers are enabled and the pod has any
|
||||
// restartable init container, we should not see any
|
||||
// NextInitContainerToStart in the actions.
|
||||
test.actions.NextInitContainerToStart = nil
|
||||
}
|
||||
verifyActions(t, &test.actions, &actions, desc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncPodWithSandboxAndDeletedPod(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fakeRuntime, _, m, err := createTestRuntimeManager()
|
||||
|
||||
@@ -807,16 +807,6 @@
|
||||
lockToDefault: true
|
||||
preRelease: GA
|
||||
version: "1.34"
|
||||
- name: LegacySidecarContainers
|
||||
versionedSpecs:
|
||||
- default: true
|
||||
lockToDefault: false
|
||||
preRelease: GA
|
||||
version: "1.0"
|
||||
- default: false
|
||||
lockToDefault: false
|
||||
preRelease: Deprecated
|
||||
version: "1.33"
|
||||
- name: ListFromCacheSnapshot
|
||||
versionedSpecs:
|
||||
- default: false
|
||||
|
||||
Reference in New Issue
Block a user