diff --git a/README.md b/README.md index ae99c3845..2b1401994 100644 --- a/README.md +++ b/README.md @@ -673,12 +673,14 @@ Pods in any state (even `Running`) are considered for eviction. **Parameters:** -|Name|Type|Notes| -|---|---|---| -|`maxPodLifeTimeSeconds`|int|| -|`states`|list(string)|Only supported in v0.25+| -|`namespaces`|(see [namespace filtering](#namespace-filtering))|| -|`labelSelector`|(see [label filtering](#label-filtering))|| +| Name | Type | Notes | +|--------------------------------|---------------------------------------------------|--------------------------| +| `maxPodLifeTimeSeconds` | int | | +| `states` | list(string) | Only supported in v0.25+ | +| `includingInitContainers` | bool | Only supported in v0.31+ | +| `includingEphemeralContainers` | bool | Only supported in v0.31+ | +| `namespaces` | (see [namespace filtering](#namespace-filtering)) | | +| `labelSelector` | (see [label filtering](#label-filtering)) | | **Example:** diff --git a/pkg/framework/plugins/podlifetime/pod_lifetime.go b/pkg/framework/plugins/podlifetime/pod_lifetime.go index 79f711f31..d451fea7c 100644 --- a/pkg/framework/plugins/podlifetime/pod_lifetime.go +++ b/pkg/framework/plugins/podlifetime/pod_lifetime.go @@ -85,6 +85,24 @@ func New(args runtime.Object, handle frameworktypes.Handle) (frameworktypes.Plug return true } + // Init Container Status Reason + if podLifeTimeArgs.IncludingInitContainers { + for _, containerStatus := range pod.Status.InitContainerStatuses { + if containerStatus.State.Waiting != nil && states.Has(containerStatus.State.Waiting.Reason) { + return true + } + } + } + + // Ephemeral Container Status Reason + if podLifeTimeArgs.IncludingEphemeralContainers { + for _, containerStatus := range pod.Status.EphemeralContainerStatuses { + if containerStatus.State.Waiting != nil && states.Has(containerStatus.State.Waiting.Reason) { + return true + } + } + } + // Container Status Reason for _, containerStatus := range pod.Status.ContainerStatuses { if containerStatus.State.Waiting != nil && states.Has(containerStatus.State.Waiting.Reason) { diff --git a/pkg/framework/plugins/podlifetime/pod_lifetime_test.go b/pkg/framework/plugins/podlifetime/pod_lifetime_test.go index e0ca64843..f34fd11c5 100644 --- a/pkg/framework/plugins/podlifetime/pod_lifetime_test.go +++ b/pkg/framework/plugins/podlifetime/pod_lifetime_test.go @@ -412,6 +412,84 @@ func TestPodLifeTime(t *testing.T) { } }, }, + { + description: "1 pod with init container status CreateContainerError should not be evicted without includingInitContainers", + args: &PodLifeTimeArgs{ + MaxPodLifeTimeSeconds: &maxLifeTime, + States: []string{"CreateContainerError"}, + }, + pods: []*v1.Pod{p9}, + nodes: []*v1.Node{node1}, + expectedEvictedPodCount: 0, + applyPodsFunc: func(pods []*v1.Pod) { + pods[0].Status.InitContainerStatuses = []v1.ContainerStatus{ + { + State: v1.ContainerState{ + Waiting: &v1.ContainerStateWaiting{Reason: "CreateContainerError"}, + }, + }, + } + }, + }, + { + description: "1 pod with init container status CreateContainerError should be evicted with includingInitContainers", + args: &PodLifeTimeArgs{ + MaxPodLifeTimeSeconds: &maxLifeTime, + States: []string{"CreateContainerError"}, + IncludingInitContainers: true, + }, + pods: []*v1.Pod{p9}, + nodes: []*v1.Node{node1}, + expectedEvictedPodCount: 1, + applyPodsFunc: func(pods []*v1.Pod) { + pods[0].Status.InitContainerStatuses = []v1.ContainerStatus{ + { + State: v1.ContainerState{ + Waiting: &v1.ContainerStateWaiting{Reason: "CreateContainerError"}, + }, + }, + } + }, + }, + { + description: "1 pod with ephemeral container status CreateContainerError should not be evicted without includingEphemeralContainers", + args: &PodLifeTimeArgs{ + MaxPodLifeTimeSeconds: &maxLifeTime, + States: []string{"CreateContainerError"}, + }, + pods: []*v1.Pod{p9}, + nodes: []*v1.Node{node1}, + expectedEvictedPodCount: 0, + applyPodsFunc: func(pods []*v1.Pod) { + pods[0].Status.InitContainerStatuses = []v1.ContainerStatus{ + { + State: v1.ContainerState{ + Waiting: &v1.ContainerStateWaiting{Reason: "CreateContainerError"}, + }, + }, + } + }, + }, + { + description: "1 pod with ephemeral container status CreateContainerError should be evicted with includingEphemeralContainers", + args: &PodLifeTimeArgs{ + MaxPodLifeTimeSeconds: &maxLifeTime, + States: []string{"CreateContainerError"}, + IncludingEphemeralContainers: true, + }, + pods: []*v1.Pod{p9}, + nodes: []*v1.Node{node1}, + expectedEvictedPodCount: 1, + applyPodsFunc: func(pods []*v1.Pod) { + pods[0].Status.EphemeralContainerStatuses = []v1.ContainerStatus{ + { + State: v1.ContainerState{ + Waiting: &v1.ContainerStateWaiting{Reason: "CreateContainerError"}, + }, + }, + } + }, + }, { description: "1 pod with container status CreateContainerError should be evicted", args: &PodLifeTimeArgs{ diff --git a/pkg/framework/plugins/podlifetime/types.go b/pkg/framework/plugins/podlifetime/types.go index 8c3079f57..62b2f07c6 100644 --- a/pkg/framework/plugins/podlifetime/types.go +++ b/pkg/framework/plugins/podlifetime/types.go @@ -25,8 +25,10 @@ import ( type PodLifeTimeArgs struct { metav1.TypeMeta `json:",inline"` - Namespaces *api.Namespaces `json:"namespaces"` - LabelSelector *metav1.LabelSelector `json:"labelSelector"` - MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds"` - States []string `json:"states"` + Namespaces *api.Namespaces `json:"namespaces"` + LabelSelector *metav1.LabelSelector `json:"labelSelector"` + MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds"` + States []string `json:"states"` + IncludingInitContainers bool `json:"includingInitContainers"` + IncludingEphemeralContainers bool `json:"includingEphemeralContainers"` }