pod-overhead: add Overhead to PodSpec internal type

Update internal PodSpec to make use of Overhead field. Add validation
and validation tests.

Signed-off-by: Eric Ernst <eric.ernst@intel.com>
This commit is contained in:
Eric Ernst 2019-04-23 14:03:50 -07:00
parent 558477455c
commit d0b0c0ae45
3 changed files with 67 additions and 0 deletions

View File

@ -2700,6 +2700,16 @@ type PodSpec struct {
// This is a beta feature as of Kubernetes v1.14.
// +optional
RuntimeClassName *string
// Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.
// This field will be autopopulated at admission time by the RuntimeClass admission controller. If
// the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.
// The RuntimeClass admission controller will reject Pod create requests which have the overhead already
// set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value
// defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.
// More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md
// This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.
// +optional
Overhead ResourceList
// EnableServiceLinks indicates whether information about services should be injected into pod's
// environment variables, matching the syntax of Docker links.
// If not specified, the default is true.

View File

@ -264,6 +264,12 @@ func ValidateRuntimeClassName(name string, fldPath *field.Path) field.ErrorList
return allErrs
}
// validateOverhead can be used to check whether the given Overhead is valid.
func validateOverhead(overhead core.ResourceList, fldPath *field.Path) field.ErrorList {
// reuse the ResourceRequirements validation logic
return ValidateResourceRequirements(&core.ResourceRequirements{Limits: overhead}, fldPath)
}
// Validates that given value is not negative.
func ValidateNonnegativeField(value int64, fldPath *field.Path) field.ErrorList {
return apimachineryvalidation.ValidateNonnegativeField(value, fldPath)
@ -3095,6 +3101,10 @@ func ValidatePodSpec(spec *core.PodSpec, fldPath *field.Path) field.ErrorList {
allErrs = append(allErrs, ValidatePreemptionPolicy(spec.PreemptionPolicy, fldPath.Child("preemptionPolicy"))...)
}
if spec.Overhead != nil && utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) {
allErrs = append(allErrs, validateOverhead(spec.Overhead, fldPath.Child("overhead"))...)
}
return allErrs
}

View File

@ -6334,6 +6334,7 @@ func TestValidatePodSpec(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodPriority, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RuntimeClass, true)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodOverhead, true)()
successCases := []core.PodSpec{
{ // Populate basic fields, leave defaults for most.
@ -6474,6 +6475,13 @@ func TestValidatePodSpec(t *testing.T) {
DNSPolicy: core.DNSClusterFirst,
RuntimeClassName: utilpointer.StringPtr("valid-sandbox"),
},
{ // Populate Overhead
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
RestartPolicy: core.RestartPolicyAlways,
DNSPolicy: core.DNSClusterFirst,
RuntimeClassName: utilpointer.StringPtr("valid-sandbox"),
Overhead: core.ResourceList{},
},
}
for i := range successCases {
if errs := ValidatePodSpec(&successCases[i], field.NewPath("field")); len(errs) != 0 {
@ -13498,3 +13506,42 @@ func TestAlphaVolumePVCDataSource(t *testing.T) {
}
}
}
func TestValidateOverhead(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodOverhead, true)()
successCase := []struct {
Name string
overhead core.ResourceList
}{
{
Name: "Valid Overhead for CPU + Memory",
overhead: core.ResourceList{
core.ResourceName(core.ResourceCPU): resource.MustParse("10"),
core.ResourceName(core.ResourceMemory): resource.MustParse("10G"),
},
},
}
for _, tc := range successCase {
if errs := validateOverhead(tc.overhead, field.NewPath("overheads")); len(errs) != 0 {
t.Errorf("%q unexpected error: %v", tc.Name, errs)
}
}
errorCase := []struct {
Name string
overhead core.ResourceList
}{
{
Name: "Invalid Overhead Resources",
overhead: core.ResourceList{
core.ResourceName("my.org"): resource.MustParse("10m"),
},
},
}
for _, tc := range errorCase {
if errs := validateOverhead(tc.overhead, field.NewPath("resources")); len(errs) == 0 {
t.Errorf("%q expected error", tc.Name)
}
}
}