Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions apis/extension/slo_controller_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type NodeCfgProfile struct {
// +k8s:deepcopy-gen=true
type ColocationCfg struct {
ColocationStrategy `json:",inline"`
NodeConfigs []NodeColocationCfg `json:"nodeConfigs,omitempty"`
NodeConfigs []NodeColocationCfg `json:"nodeConfigs,omitempty" validate:"dive"`
}

// +k8s:deepcopy-gen=true
Expand All @@ -55,7 +55,7 @@ type NodeColocationCfg struct {
// +k8s:deepcopy-gen=true
type ResourceThresholdCfg struct {
ClusterStrategy *slov1alpha1.ResourceThresholdStrategy `json:"clusterStrategy,omitempty"`
NodeStrategies []NodeResourceThresholdStrategy `json:"nodeStrategies,omitempty"`
NodeStrategies []NodeResourceThresholdStrategy `json:"nodeStrategies,omitempty" validate:"dive"`
}

// +k8s:deepcopy-gen=true
Expand All @@ -73,7 +73,7 @@ type NodeCPUBurstCfg struct {
// +k8s:deepcopy-gen=true
type CPUBurstCfg struct {
ClusterStrategy *slov1alpha1.CPUBurstStrategy `json:"clusterStrategy,omitempty"`
NodeStrategies []NodeCPUBurstCfg `json:"nodeStrategies,omitempty"`
NodeStrategies []NodeCPUBurstCfg `json:"nodeStrategies,omitempty" validate:"dive"`
}

// +k8s:deepcopy-gen=true
Expand All @@ -85,13 +85,13 @@ type NodeSystemStrategy struct {
// +k8s:deepcopy-gen=true
type SystemCfg struct {
ClusterStrategy *slov1alpha1.SystemStrategy `json:"clusterStrategy,omitempty"`
NodeStrategies []NodeSystemStrategy `json:"nodeStrategies,omitempty"`
NodeStrategies []NodeSystemStrategy `json:"nodeStrategies,omitempty" validate:"dive"`
}

// +k8s:deepcopy-gen=true
type ResourceQOSCfg struct {
ClusterStrategy *slov1alpha1.ResourceQOSStrategy `json:"clusterStrategy,omitempty"`
NodeStrategies []NodeResourceQOSStrategy `json:"nodeStrategies,omitempty"`
NodeStrategies []NodeResourceQOSStrategy `json:"nodeStrategies,omitempty" validate:"dive"`
}

// +k8s:deepcopy-gen=true
Expand Down Expand Up @@ -196,15 +196,15 @@ func (in *ExtraFields) DeepCopy() *ExtraFields {
// +k8s:deepcopy-gen=true
type ColocationStrategy struct {
Enable *bool `json:"enable,omitempty"`
MetricAggregateDurationSeconds *int64 `json:"metricAggregateDurationSeconds,omitempty"`
MetricReportIntervalSeconds *int64 `json:"metricReportIntervalSeconds,omitempty"`
MetricAggregateDurationSeconds *int64 `json:"metricAggregateDurationSeconds,omitempty" validate:"omitempty,min=1"`
MetricReportIntervalSeconds *int64 `json:"metricReportIntervalSeconds,omitempty" validate:"omitempty,min=1"`
MetricAggregatePolicy *slov1alpha1.AggregatePolicy `json:"metricAggregatePolicy,omitempty"`
CPUReclaimThresholdPercent *int64 `json:"cpuReclaimThresholdPercent,omitempty"`
MemoryReclaimThresholdPercent *int64 `json:"memoryReclaimThresholdPercent,omitempty"`
CPUReclaimThresholdPercent *int64 `json:"cpuReclaimThresholdPercent,omitempty" validate:"omitempty,min=0,max=100"`
MemoryReclaimThresholdPercent *int64 `json:"memoryReclaimThresholdPercent,omitempty" validate:"omitempty,min=0,max=100"`
MemoryCalculatePolicy *CalculatePolicy `json:"memoryCalculatePolicy,omitempty"`
DegradeTimeMinutes *int64 `json:"degradeTimeMinutes,omitempty"`
UpdateTimeThresholdSeconds *int64 `json:"updateTimeThresholdSeconds,omitempty"`
ResourceDiffThreshold *float64 `json:"resourceDiffThreshold,omitempty"`
DegradeTimeMinutes *int64 `json:"degradeTimeMinutes,omitempty" validate:"omitempty,min=1"`
UpdateTimeThresholdSeconds *int64 `json:"updateTimeThresholdSeconds,omitempty" validate:"omitempty,min=1"`
ResourceDiffThreshold *float64 `json:"resourceDiffThreshold,omitempty" validate:"omitempty,gt=0,max=1"`
ColocationStrategyExtender `json:",inline"` // for third-party extension
}

Expand Down
54 changes: 27 additions & 27 deletions apis/slo/v1alpha1/nodeslo_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
// CPUQOS enables cpu qos features.
type CPUQOS struct {
// group identity value for pods, default = 0
GroupIdentity *int64 `json:"groupIdentity,omitempty"`
GroupIdentity *int64 `json:"groupIdentity,omitempty" validate:"omitempty,min=-1,max=2"`
}

// MemoryQOS enables memory qos features.
Expand All @@ -41,21 +41,21 @@ type MemoryQOS struct {
// from global reclamation when memory usage does not exceed the min limit.
// Close: 0.
// +kubebuilder:validation:Minimum=0
MinLimitPercent *int64 `json:"minLimitPercent,omitempty"`
MinLimitPercent *int64 `json:"minLimitPercent,omitempty" validate:"omitempty,min=0,max=100"`
// LowLimitPercent specifies the lowLimitFactor percentage to calculate `memory.low`, which TRIES BEST
// protecting memory from global reclamation when memory usage does not exceed the low limit unless no unprotected
// memcg can be reclaimed.
// NOTE: `memory.low` should be larger than `memory.min`. If spec.requests.memory == spec.limits.memory,
// pod `memory.low` and `memory.high` become invalid, while `memory.wmark_ratio` is still in effect.
// Close: 0.
// +kubebuilder:validation:Minimum=0
LowLimitPercent *int64 `json:"lowLimitPercent,omitempty"`
LowLimitPercent *int64 `json:"lowLimitPercent,omitempty" validate:"omitempty,min=0,max=100"`
// ThrottlingPercent specifies the throttlingFactor percentage to calculate `memory.high` with pod
// memory.limits or node allocatable memory, which triggers memcg direct reclamation when memory usage exceeds.
// Lower the factor brings more heavier reclaim pressure.
// Close: 0.
// +kubebuilder:validation:Minimum=0
ThrottlingPercent *int64 `json:"throttlingPercent,omitempty"`
ThrottlingPercent *int64 `json:"throttlingPercent,omitempty" validate:"omitempty,min=0,max=100"`

// wmark_ratio (Anolis OS required)
// Async memory reclamation is triggered when cgroup memory usage exceeds `memory.wmark_high` and the reclamation
Expand All @@ -67,13 +67,13 @@ type MemoryQOS struct {
// Close: 0. Recommended: 95.
// +kubebuilder:validation:Maximum=100
// +kubebuilder:validation:Minimum=0
WmarkRatio *int64 `json:"wmarkRatio,omitempty"`
WmarkRatio *int64 `json:"wmarkRatio,omitempty" validate:"omitempty,min=0,max=100"`
// WmarkScalePermill specifies `memory.wmark_scale_factor` that helps calculate `memory.wmark_low`, which
// stops async memory reclamation when memory usage belows.
// Close: 50. Recommended: 20.
// +kubebuilder:validation:Maximum=1000
// +kubebuilder:validation:Minimum=1
WmarkScalePermill *int64 `json:"wmarkScalePermill,omitempty"`
WmarkScalePermill *int64 `json:"wmarkScalePermill,omitempty" validate:"omitempty,min=1,max=1000"`

// wmark_min_adj (Anolis OS required)
// WmarkMinAdj specifies `memory.wmark_min_adj` which adjusts per-memcg threshold for global memory
Expand All @@ -84,12 +84,12 @@ type MemoryQOS struct {
// Close: [LSR:0, LS:0, BE:0]. Recommended: [LSR:-25, LS:-25, BE:50].
// +kubebuilder:validation:Maximum=50
// +kubebuilder:validation:Minimum=-25
WmarkMinAdj *int64 `json:"wmarkMinAdj,omitempty"`
WmarkMinAdj *int64 `json:"wmarkMinAdj,omitempty" validate:"omitempty,min=-25,max=50"`

// TODO: enhance the usages of oom priority and oom kill group
PriorityEnable *int64 `json:"priorityEnable,omitempty"`
Priority *int64 `json:"priority,omitempty"`
OomKillGroup *int64 `json:"oomKillGroup,omitempty"`
PriorityEnable *int64 `json:"priorityEnable,omitempty" validate:"omitempty,min=0,max=1"`
Priority *int64 `json:"priority,omitempty" validate:"omitempty,min=0,max=12"`
OomKillGroup *int64 `json:"oomKillGroup,omitempty" validate:"omitempty,min=0,max=1"`
}

type PodMemoryQOSPolicy string
Expand Down Expand Up @@ -162,31 +162,31 @@ type ResourceThresholdStrategy struct {
// cpu suppress threshold percentage (0,100), default = 65
// +kubebuilder:validation:Maximum=100
// +kubebuilder:validation:Minimum=0
CPUSuppressThresholdPercent *int64 `json:"cpuSuppressThresholdPercent,omitempty"`
CPUSuppressThresholdPercent *int64 `json:"cpuSuppressThresholdPercent,omitempty" validate:"omitempty,min=0,max=100"`
// CPUSuppressPolicy
CPUSuppressPolicy CPUSuppressPolicy `json:"cpuSuppressPolicy,omitempty"`

// upper: memory evict threshold percentage (0,100), default = 70
// +kubebuilder:validation:Maximum=100
// +kubebuilder:validation:Minimum=0
MemoryEvictThresholdPercent *int64 `json:"memoryEvictThresholdPercent,omitempty"`
MemoryEvictThresholdPercent *int64 `json:"memoryEvictThresholdPercent,omitempty" validate:"omitempty,min=0,max=100,gtfield=MemoryEvictLowerPercent"`
// lower: memory release util usage under MemoryEvictLowerPercent, default = MemoryEvictThresholdPercent - 2
// +kubebuilder:validation:Maximum=100
// +kubebuilder:validation:Minimum=0
MemoryEvictLowerPercent *int64 `json:"memoryEvictLowerPercent,omitempty"`
MemoryEvictLowerPercent *int64 `json:"memoryEvictLowerPercent,omitempty" validate:"omitempty,min=0,max=100,ltfield=MemoryEvictThresholdPercent"`

// be.satisfactionRate = be.CPURealLimit/be.CPURequest
// if be.satisfactionRate > CPUEvictBESatisfactionUpperPercent/100, then stop to evict.
CPUEvictBESatisfactionUpperPercent *int64 `json:"cpuEvictBESatisfactionUpperPercent,omitempty"`
CPUEvictBESatisfactionUpperPercent *int64 `json:"cpuEvictBESatisfactionUpperPercent,omitempty" validate:"omitempty,min=0,max=100,gtfield=CPUEvictBESatisfactionLowerPercent"`
// be.satisfactionRate = be.CPURealLimit/be.CPURequest; be.cpuUsage = be.CPUUsed/be.CPURealLimit
// if be.satisfactionRate < CPUEvictBESatisfactionLowerPercent/100 && be.usage >= CPUEvictBEUsageThresholdPercent/100,
// then start to evict pod, and will evict to ${CPUEvictBESatisfactionUpperPercent}
CPUEvictBESatisfactionLowerPercent *int64 `json:"cpuEvictBESatisfactionLowerPercent,omitempty"`
CPUEvictBESatisfactionLowerPercent *int64 `json:"cpuEvictBESatisfactionLowerPercent,omitempty" validate:"omitempty,min=0,max=100,ltfield=CPUEvictBESatisfactionUpperPercent"`
// if be.cpuUsage >= CPUEvictBEUsageThresholdPercent/100, then start to calculate the resources need to be released.
CPUEvictBEUsageThresholdPercent *int64 `json:"cpuEvictBEUsageThresholdPercent,omitempty"`
CPUEvictBEUsageThresholdPercent *int64 `json:"cpuEvictBEUsageThresholdPercent,omitempty" validate:"omitempty,min=0,max=100"`
// when avg(cpuusage) > CPUEvictThresholdPercent, will start to evict pod by cpu,
// and avg(cpuusage) is calculated based on the most recent CPUEvictTimeWindowSeconds data
CPUEvictTimeWindowSeconds *int64 `json:"cpuEvictTimeWindowSeconds,omitempty"`
CPUEvictTimeWindowSeconds *int64 `json:"cpuEvictTimeWindowSeconds,omitempty" validate:"omitempty,gt=0"`
}

// ResctrlQOSCfg stores node-level config of resctrl qos
Expand All @@ -200,15 +200,15 @@ type ResctrlQOS struct {
// LLC available range start for pods by percentage
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:Maximum=100
CATRangeStartPercent *int64 `json:"catRangeStartPercent,omitempty"`
CATRangeStartPercent *int64 `json:"catRangeStartPercent,omitempty" validate:"omitempty,min=0,max=100,ltfield=CATRangeEndPercent"`
// LLC available range end for pods by percentage
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:Maximum=100
CATRangeEndPercent *int64 `json:"catRangeEndPercent,omitempty"`
CATRangeEndPercent *int64 `json:"catRangeEndPercent,omitempty" validate:"omitempty,min=0,max=100,gtfield=CATRangeStartPercent"`
// MBA percent
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:Maximum=100
MBAPercent *int64 `json:"mbaPercent,omitempty"`
MBAPercent *int64 `json:"mbaPercent,omitempty" validate:"omitempty,min=0,max=100"`
}

type CPUBurstPolicy string
Expand All @@ -229,26 +229,26 @@ type CPUBurstConfig struct {
// cpu burst percentage for setting cpu.cfs_burst_us, legal range: [0, 10000], default as 1000 (1000%)
// +kubebuilder:validation:Maximum=10000
// +kubebuilder:validation:Minimum=0
CPUBurstPercent *int64 `json:"cpuBurstPercent,omitempty"`
CPUBurstPercent *int64 `json:"cpuBurstPercent,omitempty" validate:"omitempty,min=1,max=10000"`
// pod cfs quota scale up ceil percentage, default = 300 (300%)
CFSQuotaBurstPercent *int64 `json:"cfsQuotaBurstPercent,omitempty"`
CFSQuotaBurstPercent *int64 `json:"cfsQuotaBurstPercent,omitempty" validate:"omitempty,min=100"`
// specifies a period of time for pod can use at burst, default = -1 (unlimited)
CFSQuotaBurstPeriodSeconds *int64 `json:"cfsQuotaBurstPeriodSeconds,omitempty"`
CFSQuotaBurstPeriodSeconds *int64 `json:"cfsQuotaBurstPeriodSeconds,omitempty" validate:"omitempty,min=-1"`
}

type CPUBurstStrategy struct {
CPUBurstConfig `json:",inline"`
// scale down cfs quota if node cpu overload, default = 50
SharePoolThresholdPercent *int64 `json:"sharePoolThresholdPercent,omitempty"`
SharePoolThresholdPercent *int64 `json:"sharePoolThresholdPercent,omitempty" validate:"omitempty,min=0,max=100"`
}

type SystemStrategy struct {
// for /proc/sys/vm/min_free_kbytes, min_free_kbytes = minFreeKbytesFactor * nodeTotalMemory /10000
MinFreeKbytesFactor *int64 `json:"minFreeKbytesFactor,omitempty"`
MinFreeKbytesFactor *int64 `json:"minFreeKbytesFactor,omitempty" validate:"omitempty,gt=0"`
// /proc/sys/vm/watermark_scale_factor
WatermarkScaleFactor *int64 `json:"watermarkScaleFactor,omitempty"`
WatermarkScaleFactor *int64 `json:"watermarkScaleFactor,omitempty" validate:"omitempty,gt=0,max=400"`
// /sys/kernel/mm/memcg_reaper/reap_background
MemcgReapBackGround *int64 `json:"memcgReapBackGround,omitempty"`
MemcgReapBackGround *int64 `json:"memcgReapBackGround,omitempty" validate:"omitempty,min=0,max=1"`
}

// NodeSLOSpec defines the desired state of NodeSLO
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ require (
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/fsnotify/fsnotify v1.6.0
github.com/gin-gonic/gin v1.8.1
github.com/go-playground/locales v0.14.0
github.com/go-playground/universal-translator v0.18.0
github.com/go-playground/validator/v10 v10.10.0
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
Expand Down Expand Up @@ -110,9 +113,6 @@ require (
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.10.0 // indirect
github.com/goccy/go-json v0.9.7 // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect
Expand Down
15 changes: 15 additions & 0 deletions pkg/util/sloconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,29 @@ package sloconfig

import "flag"

const (
Zh = "zh"
En = "en"
)

var (
// ConfigNameSpace is the namespace of the slo-controller configmap.
ConfigNameSpace = "koordinator-system"
// SLOCtrlConfigMap is the name of the slo-controller configmap.
SLOCtrlConfigMap = "slo-controller-config"
// DefaultTranslator = "en"
DefaultTranslator = "en"
// NodeStrategyNameNeedCheck true:enable to check name required and not conflict, false: not check
NodeStrategyNameNeedCheck = "false"
)

func InitFlags(fs *flag.FlagSet) {
fs.StringVar(&SLOCtrlConfigMap, "slo-config-name", SLOCtrlConfigMap, "determines the name the slo-controller configmap uses.")
fs.StringVar(&ConfigNameSpace, "config-namespace", ConfigNameSpace, "determines the namespace of configmap uses.")
fs.StringVar(&DefaultTranslator, "default-config-translator", DefaultTranslator, "determines the sloConfig validator translator. e.g. 'en', 'zh'")
fs.StringVar(&NodeStrategyNameNeedCheck, "node-strategy-name-need-check", NodeStrategyNameNeedCheck, "determines the sloConfig validator nodeConfig name check enable, 'true':enable, 'false':unable, default:false.")
}

func IsNodeStrategyNameNeedCheck() bool {
return NodeStrategyNameNeedCheck == "true"
}
89 changes: 89 additions & 0 deletions pkg/util/sloconfig/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2022 The Koordinator Authors.

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 sloconfig

import (
"sync"

"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
transen "github.com/go-playground/validator/v10/translations/en"
transzh "github.com/go-playground/validator/v10/translations/zh"
)

var validatorInstance = &DefaultValidator{}

type DefaultValidator struct {
once sync.Once
validator *validator.Validate
trans *ut.Translator
}

// StructWithTrans support en or zh translator
func (v *DefaultValidator) StructWithTrans(config interface{}) (validator.ValidationErrorsTranslations, error) {
err := v.validator.Struct(config)
switch err.(type) {
case validator.ValidationErrors:
if v.trans != nil {
return err.(validator.ValidationErrors).Translate(*v.trans), nil
}
default:
}
return nil, err
}

func GetValidatorInstance() *DefaultValidator {
validatorInstance.once.Do(func() {
validatorInstance.validator, validatorInstance.trans = createValidator()
})
return validatorInstance
}

func createValidator() (*validator.Validate, *ut.Translator) {
instance := validator.New()
switch DefaultTranslator {
case Zh:
return instance, registerZhTranslator(instance)
case En:
return instance, registerEnTranslator(instance)
default:
return instance, registerEnTranslator(instance)
}
}

func registerEnTranslator(instance *validator.Validate) *ut.Translator {
locale := en.New()
uni := ut.New(locale, locale)
trans, _ := uni.GetTranslator(En)
err := transen.RegisterDefaultTranslations(instance, trans)
if err != nil {
return nil
}
return &trans
}

func registerZhTranslator(instance *validator.Validate) *ut.Translator {
locale := zh.New()
uni := ut.New(locale, locale)
trans, _ := uni.GetTranslator(Zh)
err := transzh.RegisterDefaultTranslations(instance, trans)
if err != nil {
return nil
}
return &trans
}
Loading