Merge pull request #29400 from derekwaynecarr/min-reclaim-parse

Automatic merge from submit-queue

Add parsing code in kubelet for eviction-minimum-reclaim

The kubelet parses the eviction-minimum-reclaim flag and validates it for correctness.

The first two commits are from https://github.com/kubernetes/kubernetes/pull/29329 which has already achieved LGTM.
This commit is contained in:
k8s-merge-robot 2016-07-22 21:35:35 -07:00 committed by GitHub
commit 2e53a24889
4 changed files with 79 additions and 7 deletions

View File

@ -187,7 +187,7 @@ func UnsecuredKubeletConfig(s *options.KubeletServer) (*KubeletConfig, error) {
return nil, err
}
thresholds, err := eviction.ParseThresholdConfig(s.EvictionHard, s.EvictionSoft, s.EvictionSoftGracePeriod)
thresholds, err := eviction.ParseThresholdConfig(s.EvictionHard, s.EvictionSoft, s.EvictionSoftGracePeriod, s.EvictionMinimumReclaim)
if err != nil {
return nil, err
}

View File

@ -65,7 +65,7 @@ func validSignal(signal Signal) bool {
}
// ParseThresholdConfig parses the flags for thresholds.
func ParseThresholdConfig(evictionHard, evictionSoft, evictionSoftGracePeriod string) ([]Threshold, error) {
func ParseThresholdConfig(evictionHard, evictionSoft, evictionSoftGracePeriod, evictionMinimumReclaim string) ([]Threshold, error) {
results := []Threshold{}
hardThresholds, err := parseThresholdStatements(evictionHard)
@ -82,6 +82,10 @@ func ParseThresholdConfig(evictionHard, evictionSoft, evictionSoftGracePeriod st
if err != nil {
return nil, err
}
minReclaims, err := parseMinimumReclaims(evictionMinimumReclaim)
if err != nil {
return nil, err
}
for i := range softThresholds {
signal := softThresholds[i].Signal
period, found := gracePeriods[signal]
@ -91,6 +95,14 @@ func ParseThresholdConfig(evictionHard, evictionSoft, evictionSoftGracePeriod st
softThresholds[i].GracePeriod = period
}
results = append(results, softThresholds...)
for i := range results {
for signal, minReclaim := range minReclaims {
if results[i].Signal == signal {
results[i].MinReclaim = &minReclaim
break
}
}
}
return results, nil
}
@ -186,6 +198,38 @@ func parseGracePeriods(expr string) (map[Signal]time.Duration, error) {
return results, nil
}
// parseMinimumReclaims parses the minimum reclaim statements
func parseMinimumReclaims(expr string) (map[Signal]resource.Quantity, error) {
if len(expr) == 0 {
return nil, nil
}
results := map[Signal]resource.Quantity{}
statements := strings.Split(expr, ",")
for _, statement := range statements {
parts := strings.Split(statement, "=")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid eviction minimum reclaim syntax: %v, expected <signal>=<quantity>", statement)
}
signal := Signal(parts[0])
if !validSignal(signal) {
return nil, fmt.Errorf(unsupportedEvictionSignal, signal)
}
// check against duplicate statements
if _, found := results[signal]; found {
return nil, fmt.Errorf("duplicate eviction minimum reclaim specified for %v", signal)
}
quantity, err := resource.ParseQuantity(parts[1])
if quantity.Sign() < 0 {
return nil, fmt.Errorf("negative eviction minimum reclaim specified for %v", signal)
}
if err != nil {
return nil, err
}
results[signal] = quantity
}
return results, nil
}
// diskUsage converts used bytes into a resource quantity.
func diskUsage(fsStats *statsapi.FsStats) *resource.Quantity {
if fsStats == nil || fsStats.UsedBytes == nil {

View File

@ -41,6 +41,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard string
evictionSoft string
evictionSoftGracePeriod string
evictionMinReclaim string
expectErr bool
expectThresholds []Threshold
}{
@ -48,6 +49,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "",
expectErr: false,
expectThresholds: []Threshold{},
},
@ -55,18 +57,21 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "memory.available<150Mi",
evictionSoft: "memory.available<300Mi",
evictionSoftGracePeriod: "memory.available=30s",
evictionMinReclaim: "memory.available=0",
expectErr: false,
expectThresholds: []Threshold{
{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: quantityMustParse("150Mi"),
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: quantityMustParse("150Mi"),
MinReclaim: quantityMustParse("0"),
},
{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: quantityMustParse("300Mi"),
GracePeriod: gracePeriod,
MinReclaim: quantityMustParse("0"),
},
},
},
@ -74,6 +79,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "mem.available<150Mi",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "",
expectErr: true,
expectThresholds: []Threshold{},
},
@ -81,6 +87,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "memory.available<150Mi,memory.available<100Mi",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "",
expectErr: true,
expectThresholds: []Threshold{},
},
@ -88,6 +95,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "memory.available<150Mi,invalid.foo<150Mi",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "",
expectErr: true,
expectThresholds: []Threshold{},
},
@ -95,6 +103,7 @@ func TestParseThresholdConfig(t *testing.T) {
evictionHard: "",
evictionSoft: "memory.available<150Mi",
evictionSoftGracePeriod: "",
evictionMinReclaim: "",
expectErr: true,
expectThresholds: []Threshold{},
},
@ -105,9 +114,25 @@ func TestParseThresholdConfig(t *testing.T) {
expectErr: true,
expectThresholds: []Threshold{},
},
"neg-reclaim": {
evictionHard: "",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "memory.available=-300Mi",
expectErr: true,
expectThresholds: []Threshold{},
},
"duplicate-reclaim": {
evictionHard: "",
evictionSoft: "",
evictionSoftGracePeriod: "",
evictionMinReclaim: "memory.available=-300Mi,memory.available=-100Mi",
expectErr: true,
expectThresholds: []Threshold{},
},
}
for testName, testCase := range testCases {
thresholds, err := ParseThresholdConfig(testCase.evictionHard, testCase.evictionSoft, testCase.evictionSoftGracePeriod)
thresholds, err := ParseThresholdConfig(testCase.evictionHard, testCase.evictionSoft, testCase.evictionSoftGracePeriod, testCase.evictionMinReclaim)
if testCase.expectErr != (err != nil) {
t.Errorf("Err not as expected, test: %v, error expected: %v, actual: %v", testName, testCase.expectErr, err)
}
@ -150,7 +175,8 @@ func thresholdEqual(a Threshold, b Threshold) bool {
return a.GracePeriod == b.GracePeriod &&
a.Operator == b.Operator &&
a.Signal == b.Signal &&
a.Value.Cmp(*b.Value) == 0
a.Value.Cmp(*b.Value) == 0 &&
a.MinReclaim.Cmp(*b.MinReclaim) == 0
}
// TestOrderedByQoS ensures we order BestEffort < Burstable < Guaranteed

View File

@ -60,6 +60,8 @@ type Threshold struct {
Value *resource.Quantity
// GracePeriod represents the amount of time that a threshold must be met before eviction is triggered.
GracePeriod time.Duration
// MinReclaim represents the minimum amount of resource to reclaim if the threshold is met.
MinReclaim *resource.Quantity
}
// Manager evaluates when an eviction threshold for node stability has been met on the node.