mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-20 09:33:52 +00:00
Implement pod deletion cost
This commit is contained in:
@@ -345,29 +345,34 @@ func usesMultipleHugePageResources(podSpec *api.PodSpec) bool {
|
||||
return len(hugePageResources) > 1
|
||||
}
|
||||
|
||||
// GetValidationOptionsFromPodSpec returns validation options based on pod specs
|
||||
func GetValidationOptionsFromPodSpec(podSpec, oldPodSpec *api.PodSpec) apivalidation.PodValidationOptions {
|
||||
// GetValidationOptionsFromPodSpecAndMeta returns validation options based on pod specs and metadata
|
||||
func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, podMeta, oldPodMeta *metav1.ObjectMeta) apivalidation.PodValidationOptions {
|
||||
// default pod validation options based on feature gate
|
||||
opts := validation.PodValidationOptions{
|
||||
// Allow multiple huge pages on pod create if feature is enabled
|
||||
AllowMultipleHugePageResources: utilfeature.DefaultFeatureGate.Enabled(features.HugePageStorageMediumSize),
|
||||
// Allow pod spec to use hugepages in downward API if feature is enabled
|
||||
AllowDownwardAPIHugePages: utilfeature.DefaultFeatureGate.Enabled(features.DownwardAPIHugePages),
|
||||
AllowDownwardAPIHugePages: utilfeature.DefaultFeatureGate.Enabled(features.DownwardAPIHugePages),
|
||||
AllowInvalidPodDeletionCost: !utilfeature.DefaultFeatureGate.Enabled(features.PodDeletionCost),
|
||||
}
|
||||
// if we are not doing an update operation, just return with default options
|
||||
if oldPodSpec == nil {
|
||||
return opts
|
||||
|
||||
if oldPodSpec != nil {
|
||||
// if old spec used multiple huge page sizes, we must allow it
|
||||
opts.AllowMultipleHugePageResources = opts.AllowMultipleHugePageResources || usesMultipleHugePageResources(oldPodSpec)
|
||||
// if old spec used hugepages in downward api, we must allow it
|
||||
opts.AllowDownwardAPIHugePages = opts.AllowDownwardAPIHugePages || usesHugePagesInProjectedVolume(oldPodSpec)
|
||||
// determine if any container is using hugepages in env var
|
||||
if !opts.AllowDownwardAPIHugePages {
|
||||
VisitContainers(oldPodSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||
opts.AllowDownwardAPIHugePages = opts.AllowDownwardAPIHugePages || usesHugePagesInProjectedEnv(*c)
|
||||
return !opts.AllowDownwardAPIHugePages
|
||||
})
|
||||
}
|
||||
}
|
||||
// if old spec used multiple huge page sizes, we must allow it
|
||||
opts.AllowMultipleHugePageResources = opts.AllowMultipleHugePageResources || usesMultipleHugePageResources(oldPodSpec)
|
||||
// if old spec used hugepages in downward api, we must allow it
|
||||
opts.AllowDownwardAPIHugePages = opts.AllowDownwardAPIHugePages || usesHugePagesInProjectedVolume(oldPodSpec)
|
||||
// determine if any container is using hugepages in env var
|
||||
if !opts.AllowDownwardAPIHugePages {
|
||||
VisitContainers(oldPodSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||
opts.AllowDownwardAPIHugePages = opts.AllowDownwardAPIHugePages || usesHugePagesInProjectedEnv(*c)
|
||||
return !opts.AllowDownwardAPIHugePages
|
||||
})
|
||||
if oldPodMeta != nil && !opts.AllowInvalidPodDeletionCost {
|
||||
// This is an update, so validate only if the existing object was valid.
|
||||
_, err := helper.GetDeletionCostFromPodAnnotations(oldPodMeta.Annotations)
|
||||
opts.AllowInvalidPodDeletionCost = err != nil
|
||||
}
|
||||
return opts
|
||||
}
|
||||
@@ -375,15 +380,18 @@ func GetValidationOptionsFromPodSpec(podSpec, oldPodSpec *api.PodSpec) apivalida
|
||||
// GetValidationOptionsFromPodTemplate will return pod validation options for specified template.
|
||||
func GetValidationOptionsFromPodTemplate(podTemplate, oldPodTemplate *api.PodTemplateSpec) apivalidation.PodValidationOptions {
|
||||
var newPodSpec, oldPodSpec *api.PodSpec
|
||||
var newPodMeta, oldPodMeta *metav1.ObjectMeta
|
||||
// we have to be careful about nil pointers here
|
||||
// replication controller in particular is prone to passing nil
|
||||
if podTemplate != nil {
|
||||
newPodSpec = &podTemplate.Spec
|
||||
newPodMeta = &podTemplate.ObjectMeta
|
||||
}
|
||||
if oldPodTemplate != nil {
|
||||
oldPodSpec = &oldPodTemplate.Spec
|
||||
oldPodMeta = &oldPodTemplate.ObjectMeta
|
||||
}
|
||||
return GetValidationOptionsFromPodSpec(newPodSpec, oldPodSpec)
|
||||
return GetValidationOptionsFromPodSpecAndMeta(newPodSpec, oldPodSpec, newPodMeta, oldPodMeta)
|
||||
}
|
||||
|
||||
// DropDisabledTemplateFields removes disabled fields from the pod template metadata and spec.
|
||||
|
@@ -32,6 +32,7 @@ import (
|
||||
"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/apis/core"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
@@ -1328,3 +1329,53 @@ func TestDropEphemeralContainers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePodDeletionCostOption(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
oldPodMeta *metav1.ObjectMeta
|
||||
featureEnabled bool
|
||||
wantAllowInvalidPodDeletionCost bool
|
||||
}{
|
||||
{
|
||||
name: "CreateFeatureEnabled",
|
||||
featureEnabled: true,
|
||||
wantAllowInvalidPodDeletionCost: false,
|
||||
},
|
||||
{
|
||||
name: "CreateFeatureDisabled",
|
||||
featureEnabled: false,
|
||||
wantAllowInvalidPodDeletionCost: true,
|
||||
},
|
||||
{
|
||||
name: "UpdateFeatureDisabled",
|
||||
oldPodMeta: &metav1.ObjectMeta{Annotations: map[string]string{core.PodDeletionCost: "100"}},
|
||||
featureEnabled: false,
|
||||
wantAllowInvalidPodDeletionCost: true,
|
||||
},
|
||||
{
|
||||
name: "UpdateFeatureEnabledValidOldValue",
|
||||
oldPodMeta: &metav1.ObjectMeta{Annotations: map[string]string{core.PodDeletionCost: "100"}},
|
||||
featureEnabled: true,
|
||||
wantAllowInvalidPodDeletionCost: false,
|
||||
},
|
||||
{
|
||||
name: "UpdateFeatureEnabledValidOldValue",
|
||||
oldPodMeta: &metav1.ObjectMeta{Annotations: map[string]string{core.PodDeletionCost: "invalid-value"}},
|
||||
featureEnabled: true,
|
||||
wantAllowInvalidPodDeletionCost: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodDeletionCost, tc.featureEnabled)()
|
||||
// The new pod doesn't impact the outcome.
|
||||
gotOptions := GetValidationOptionsFromPodSpecAndMeta(nil, nil, nil, tc.oldPodMeta)
|
||||
if tc.wantAllowInvalidPodDeletionCost != gotOptions.AllowInvalidPodDeletionCost {
|
||||
t.Errorf("unexpected diff, want: %v, got: %v", tc.wantAllowInvalidPodDeletionCost, gotOptions.AllowInvalidPodDeletionCost)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user