165 lines
4.6 KiB
Go
165 lines
4.6 KiB
Go
/*
|
|
Copyright 2016 The Kubernetes Authors All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package eviction
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"k8s.io/kubernetes/pkg/api"
|
|
"k8s.io/kubernetes/pkg/api/resource"
|
|
"k8s.io/kubernetes/pkg/util/sets"
|
|
)
|
|
|
|
const (
|
|
unsupportedEvictionSignal = "unsupported eviction signal %v"
|
|
)
|
|
|
|
// signalToResource maps a Signal to its associated Resource.
|
|
var signalToResource = map[Signal]api.ResourceName{
|
|
SignalMemoryAvailable: api.ResourceMemory,
|
|
}
|
|
|
|
// validSignal returns true if the signal is supported.
|
|
func validSignal(signal Signal) bool {
|
|
_, found := signalToResource[signal]
|
|
return found
|
|
}
|
|
|
|
// ParseThresholdConfig parses the flags for thresholds.
|
|
func ParseThresholdConfig(evictionHard, evictionSoft, evictionSoftGracePeriod string) ([]Threshold, error) {
|
|
results := []Threshold{}
|
|
|
|
hardThresholds, err := parseThresholdStatements(evictionHard)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
results = append(results, hardThresholds...)
|
|
|
|
softThresholds, err := parseThresholdStatements(evictionSoft)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
gracePeriods, err := parseGracePeriods(evictionSoftGracePeriod)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := range softThresholds {
|
|
signal := softThresholds[i].Signal
|
|
period, found := gracePeriods[signal]
|
|
if !found {
|
|
return nil, fmt.Errorf("grace period must be specified for the soft eviction threshold %v", signal)
|
|
}
|
|
softThresholds[i].GracePeriod = period
|
|
}
|
|
results = append(results, softThresholds...)
|
|
return results, nil
|
|
}
|
|
|
|
// parseThresholdStatements parses the input statements into a list of Threshold objects.
|
|
func parseThresholdStatements(expr string) ([]Threshold, error) {
|
|
if len(expr) == 0 {
|
|
return nil, nil
|
|
}
|
|
results := []Threshold{}
|
|
statements := strings.Split(expr, ",")
|
|
signalsFound := sets.NewString()
|
|
for _, statement := range statements {
|
|
result, err := parseThresholdStatement(statement)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if signalsFound.Has(string(result.Signal)) {
|
|
return nil, fmt.Errorf("found duplicate eviction threshold for signal %v", result.Signal)
|
|
}
|
|
signalsFound.Insert(string(result.Signal))
|
|
results = append(results, result)
|
|
}
|
|
return results, nil
|
|
}
|
|
|
|
// parseThresholdStatement parses a threshold statement.
|
|
func parseThresholdStatement(statement string) (Threshold, error) {
|
|
tokens2Operator := map[string]ThresholdOperator{
|
|
"<": OpLessThan,
|
|
}
|
|
var (
|
|
operator ThresholdOperator
|
|
parts []string
|
|
)
|
|
for token := range tokens2Operator {
|
|
parts = strings.Split(statement, token)
|
|
// if we got a token, we know this was the operator...
|
|
if len(parts) > 1 {
|
|
operator = tokens2Operator[token]
|
|
break
|
|
}
|
|
}
|
|
if len(operator) == 0 || len(parts) != 2 {
|
|
return Threshold{}, fmt.Errorf("invalid eviction threshold syntax %v, expected <signal><operator><value>", statement)
|
|
}
|
|
signal := Signal(parts[0])
|
|
if !validSignal(signal) {
|
|
return Threshold{}, fmt.Errorf(unsupportedEvictionSignal, signal)
|
|
}
|
|
|
|
quantity, err := resource.ParseQuantity(parts[1])
|
|
if err != nil {
|
|
return Threshold{}, err
|
|
}
|
|
return Threshold{
|
|
Signal: signal,
|
|
Operator: operator,
|
|
Value: *quantity,
|
|
}, nil
|
|
}
|
|
|
|
// parseGracePeriods parses the grace period statements
|
|
func parseGracePeriods(expr string) (map[Signal]time.Duration, error) {
|
|
if len(expr) == 0 {
|
|
return nil, nil
|
|
}
|
|
results := map[Signal]time.Duration{}
|
|
statements := strings.Split(expr, ",")
|
|
for _, statement := range statements {
|
|
parts := strings.Split(statement, "=")
|
|
if len(parts) != 2 {
|
|
return nil, fmt.Errorf("invalid eviction grace period syntax %v, expected <signal>=<duration>", statement)
|
|
}
|
|
signal := Signal(parts[0])
|
|
if !validSignal(signal) {
|
|
return nil, fmt.Errorf(unsupportedEvictionSignal, signal)
|
|
}
|
|
|
|
gracePeriod, err := time.ParseDuration(parts[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if gracePeriod < 0 {
|
|
return nil, fmt.Errorf("invalid eviction grace period specified: %v, must be a positive value", parts[1])
|
|
}
|
|
|
|
// check against duplicate statements
|
|
if _, found := results[signal]; found {
|
|
return nil, fmt.Errorf("duplicate eviction grace period specified for %v", signal)
|
|
}
|
|
results[signal] = gracePeriod
|
|
}
|
|
return results, nil
|
|
}
|