Skip to content

Commit

Permalink
PodLifeTime: add States field and deprecate PodStatusPhases
Browse files Browse the repository at this point in the history
  • Loading branch information
a7i committed Jun 17, 2022
1 parent 4e710cd commit 53553a9
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 28 deletions.
11 changes: 7 additions & 4 deletions README.md
Expand Up @@ -524,15 +524,17 @@ strategies:

This strategy evicts pods that are older than `maxPodLifeTimeSeconds`.

You can also specify `podStatusPhases` to `only` evict pods with specific `StatusPhases`, currently this parameter is limited
to `Running` and `Pending`.
You can also specify `states` parameter to **only** evict pods matching the following conditions:
- [Pod Phase](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase) status of: `Running`, `Pending`
- [Container State Waiting](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-state-waiting) condition of: `PodInitializing`, `ContainerCreating`

**Parameters:**

|Name|Type|
|---|---|
|`maxPodLifeTimeSeconds`|int|
|`podStatusPhases`|list(string)|
|`podStatusPhases` (**Deprecated**. Use `states` instead)|list(string)|
|`states`|list(string)|
|`thresholdPriority`|int (see [priority filtering](#priority-filtering))|
|`thresholdPriorityClassName`|string (see [priority filtering](#priority-filtering))|
|`namespaces`|(see [namespace filtering](#namespace-filtering))|
Expand All @@ -549,8 +551,9 @@ strategies:
params:
podLifeTime:
maxPodLifeTimeSeconds: 86400
podStatusPhases:
states:
- "Pending"
- "PodInitializing"
```

### RemoveFailedPods
Expand Down
3 changes: 3 additions & 0 deletions examples/pod-life-time.yml
Expand Up @@ -6,3 +6,6 @@ strategies:
params:
podLifeTime:
maxPodLifeTimeSeconds: 604800 # 7 days
states:
- "Pending"
- "PodInitializing"
5 changes: 4 additions & 1 deletion pkg/api/types.go
Expand Up @@ -113,7 +113,10 @@ type RemoveDuplicates struct {

type PodLifeTime struct {
MaxPodLifeTimeSeconds *uint
PodStatusPhases []string
States []string

// Deprecated: Use States instead.
PodStatusPhases []string
}

type FailedPods struct {
Expand Down
5 changes: 4 additions & 1 deletion pkg/api/v1alpha1/types.go
Expand Up @@ -111,7 +111,10 @@ type RemoveDuplicates struct {

type PodLifeTime struct {
MaxPodLifeTimeSeconds *uint `json:"maxPodLifeTimeSeconds,omitempty"`
PodStatusPhases []string `json:"podStatusPhases,omitempty"`
States []string `json:"states,omitempty"`

// Deprecated: Use States instead.
PodStatusPhases []string `json:"podStatusPhases,omitempty"`
}

type FailedPods struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/v1alpha1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/api/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 24 additions & 19 deletions pkg/descheduler/strategies/pod_lifetime.go
Expand Up @@ -32,7 +32,7 @@ import (
)

var (
podLifetimeAllowedPhases = sets.NewString(
podLifeTimeAllowedStates = sets.NewString(
string(v1.PodRunning),
string(v1.PodPending),

Expand All @@ -42,31 +42,37 @@ var (
)
)

func validatePodLifeTimeParams(params *api.StrategyParameters) error {
func validatePodLifeTimeParams(params *api.StrategyParameters) ([]string, error) {
if params == nil || params.PodLifeTime == nil || params.PodLifeTime.MaxPodLifeTimeSeconds == nil {
return fmt.Errorf("MaxPodLifeTimeSeconds not set")
return nil, fmt.Errorf("MaxPodLifeTimeSeconds not set")
}

var states []string
if params.PodLifeTime.PodStatusPhases != nil {
if !podLifetimeAllowedPhases.HasAll(params.PodLifeTime.PodStatusPhases...) {
return fmt.Errorf("PodStatusPhases must be one of %v", podLifetimeAllowedPhases.List())
}
states = append(states, params.PodLifeTime.PodStatusPhases...)
}
if params.PodLifeTime.States != nil {
states = append(states, params.PodLifeTime.States...)
}
if !podLifeTimeAllowedStates.HasAll(states...) {
return nil, fmt.Errorf("states must be one of %v", podLifeTimeAllowedStates.List())
}

// At most one of include/exclude can be set
if params.Namespaces != nil && len(params.Namespaces.Include) > 0 && len(params.Namespaces.Exclude) > 0 {
return fmt.Errorf("only one of Include/Exclude namespaces can be set")
return nil, fmt.Errorf("only one of Include/Exclude namespaces can be set")
}
if params.ThresholdPriority != nil && params.ThresholdPriorityClassName != "" {
return fmt.Errorf("only one of thresholdPriority and thresholdPriorityClassName can be set")
return nil, fmt.Errorf("only one of thresholdPriority and thresholdPriorityClassName can be set")
}

return nil
return states, nil
}

// PodLifeTime evicts pods on nodes that were created more than strategy.Params.MaxPodLifeTimeSeconds seconds ago.
func PodLifeTime(ctx context.Context, client clientset.Interface, strategy api.DeschedulerStrategy, nodes []*v1.Node, podEvictor *evictions.PodEvictor, evictorFilter *evictions.EvictorFilter, getPodsAssignedToNode podutil.GetPodsAssignedToNodeFunc) {
if err := validatePodLifeTimeParams(strategy.Params); err != nil {
states, err := validatePodLifeTimeParams(strategy.Params)
if err != nil {
klog.ErrorS(err, "Invalid PodLifeTime parameters")
return
}
Expand All @@ -78,22 +84,21 @@ func PodLifeTime(ctx context.Context, client clientset.Interface, strategy api.D
}

filter := evictorFilter.Filter
if strategy.Params.PodLifeTime.PodStatusPhases != nil {
filter = func(pod *v1.Pod) bool {
for _, phase := range strategy.Params.PodLifeTime.PodStatusPhases {
if string(pod.Status.Phase) == phase {
return evictorFilter.Filter(pod)
if len(states) > 0 {
filter = podutil.WrapFilterFuncs(func(pod *v1.Pod) bool {
for _, state := range states {
if string(pod.Status.Phase) == state {
return true
}

for _, containerStatus := range pod.Status.ContainerStatuses {
if containerStatus.State.Waiting != nil && containerStatus.State.Waiting.Reason == phase {
return evictable.IsEvictable(pod)
if containerStatus.State.Waiting != nil && containerStatus.State.Waiting.Reason == state {
return true
}
}
}

return false
}
}, filter)
}

podFilter, err := podutil.NewOptions().
Expand Down
8 changes: 5 additions & 3 deletions pkg/descheduler/strategies/pod_lifetime_test.go
Expand Up @@ -203,7 +203,7 @@ func TestPodLifeTime(t *testing.T) {
Params: &api.StrategyParameters{
PodLifeTime: &api.PodLifeTime{
MaxPodLifeTimeSeconds: &maxLifeTime,
PodStatusPhases: []string{"ContainerCreating"},
States: []string{"ContainerCreating"},
},
},
},
Expand All @@ -218,6 +218,7 @@ func TestPodLifeTime(t *testing.T) {
},
}
pod.OwnerReferences = ownerRef1
pod.ObjectMeta.CreationTimestamp = olderPodCreationTime
}),
},
nodes: []*v1.Node{node1},
Expand All @@ -230,7 +231,7 @@ func TestPodLifeTime(t *testing.T) {
Params: &api.StrategyParameters{
PodLifeTime: &api.PodLifeTime{
MaxPodLifeTimeSeconds: &maxLifeTime,
PodStatusPhases: []string{"PodInitializing"},
States: []string{"PodInitializing"},
},
},
},
Expand All @@ -245,6 +246,7 @@ func TestPodLifeTime(t *testing.T) {
},
}
pod.OwnerReferences = ownerRef1
pod.ObjectMeta.CreationTimestamp = olderPodCreationTime
}),
},
nodes: []*v1.Node{node1},
Expand All @@ -257,7 +259,7 @@ func TestPodLifeTime(t *testing.T) {
Params: &api.StrategyParameters{
PodLifeTime: &api.PodLifeTime{
MaxPodLifeTimeSeconds: &maxLifeTime,
PodStatusPhases: []string{"Pending"},
States: []string{"Pending"},
},
},
},
Expand Down

0 comments on commit 53553a9

Please sign in to comment.