1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 05:14:13 +01:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Avesh Agarwal
9f38146bbf Merge pull request #34 from aveshagarwal/master-remove-deadcode
Remove unused test code.
2017-11-10 17:06:05 -05:00
Avesh Agarwal
1473e1d024 Remove unused test code. 2017-11-10 16:18:07 -05:00
Avesh Agarwal
7b4b9d9e7e Merge pull request #35 from aveshagarwal/master-fixes
Fix to not process empty node list and also fix error reporting in other places.
2017-11-10 16:14:11 -05:00
Avesh Agarwal
7d079813e5 Fix to not process empty node list and also fix error reporting in other places.
Also fix unit test panic and if nodeLister is nil and refactor some code.
2017-11-10 16:09:33 -05:00
Avesh Agarwal
e02857e00a Merge pull request #33 from aveshagarwal/master-node-selector
Implement node selectors to retrieve node list based on provided query.
2017-11-10 12:11:10 -05:00
Avesh Agarwal
acfd4f8680 Update auto-generated files. 2017-11-10 12:02:43 -05:00
Avesh Agarwal
c29c9db41e Implement node selectors to retrieve node list based on provided query. 2017-11-10 12:02:43 -05:00
Avesh Agarwal
5d3f987dde Merge pull request #20 from ravisantoshgudimetla/pod-anti-affinity-strategy
Pod antiaffinity strategy
2017-11-08 10:19:16 -05:00
ravisantoshgudimetla
97732cf62d Pod antiaffinity strategy.
Signed-off-by: ravisantoshgudimetla <ravisantoshgudimetla@gmail.com>
2017-11-02 18:09:44 -04:00
Avesh Agarwal
4afc4dfb16 Merge pull request #25 from ravisantoshgudimetla/descheduler-version
Introducing versioning in descheduler
2017-10-25 17:11:07 -04:00
ravisantoshgudimetla
023ccd99f5 Introducing versioning in descheduler
Signed-off-by: ravisantoshgudimetla <ravisantoshgudimetla@gmail.com>
2017-10-24 15:45:45 -04:00
16 changed files with 631 additions and 208 deletions

View File

@@ -15,15 +15,22 @@
.PHONY: test .PHONY: test
# VERSION is currently based on the last commit # VERSION is currently based on the last commit
VERSION:=$(shell git rev-parse --short HEAD) VERSION=`git describe --tags`
COMMIT=`git rev-parse HEAD`
BUILD=`date +%FT%T%z`
LDFLAG_LOCATION=github.com/kubernetes-incubator/descheduler/cmd/descheduler/app
LDFLAGS=-ldflags "-X ${LDFLAG_LOCATION}.version=${VERSION} -X ${LDFLAG_LOCATION}.buildDate=${BUILD} -X ${LDFLAG_LOCATION}.gitCommit=${COMMIT}"
# IMAGE is the image name of descheduler # IMAGE is the image name of descheduler
# Should this be changed?
IMAGE:=descheduler:$(VERSION) IMAGE:=descheduler:$(VERSION)
all: build all: build
build: build:
go build -o _output/bin/descheduler github.com/kubernetes-incubator/descheduler/cmd/descheduler go build ${LDFLAGS} -o _output/bin/descheduler github.com/kubernetes-incubator/descheduler/cmd/descheduler
image: build image: build
docker build -t $(IMAGE) . docker build -t $(IMAGE) .

View File

@@ -53,4 +53,6 @@ func (rs *DeschedulerServer) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&rs.KubeconfigFile, "kubeconfig-file", rs.KubeconfigFile, "File with kube configuration.") fs.StringVar(&rs.KubeconfigFile, "kubeconfig-file", rs.KubeconfigFile, "File with kube configuration.")
fs.StringVar(&rs.PolicyConfigFile, "policy-config-file", rs.PolicyConfigFile, "File with descheduler policy configuration.") fs.StringVar(&rs.PolicyConfigFile, "policy-config-file", rs.PolicyConfigFile, "File with descheduler policy configuration.")
fs.BoolVar(&rs.DryRun, "dry-run", rs.DryRun, "execute descheduler in dry run mode.") fs.BoolVar(&rs.DryRun, "dry-run", rs.DryRun, "execute descheduler in dry run mode.")
// node-selector query causes descheduler to run only on nodes that matches the node labels in the query
fs.StringVar(&rs.NodeSelector, "node-selector", rs.NodeSelector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
} }

View File

@@ -19,12 +19,12 @@ package app
import ( import (
"flag" "flag"
"fmt"
"io" "io"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options" "github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler" "github.com/kubernetes-incubator/descheduler/pkg/descheduler"
"github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
aflag "k8s.io/apiserver/pkg/util/flag" aflag "k8s.io/apiserver/pkg/util/flag"
@@ -43,7 +43,7 @@ func NewDeschedulerCommand(out io.Writer) *cobra.Command {
defer logs.FlushLogs() defer logs.FlushLogs()
err := Run(s) err := Run(s)
if err != nil { if err != nil {
fmt.Println(err) glog.Errorf("%v", err)
} }
}, },
} }

View File

@@ -0,0 +1,86 @@
/*
Copyright 2017 The Kubernetes 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 app
import (
"fmt"
"github.com/spf13/cobra"
"runtime"
"strings"
)
var (
// gitCommit is a constant representing the source version that
// generated this build. It should be set during build via -ldflags.
gitCommit string
// version is a constant representing the version tag that
// generated this build. It should be set during build via -ldflags.
version string
// buildDate in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
//It should be set during build via -ldflags.
buildDate string
)
// Info holds the information related to descheduler app version.
type Info struct {
Major string `json:"major"`
Minor string `json:"minor"`
GitCommit string `json:"gitCommit"`
GitVersion string `json:"gitVersion"`
BuildDate string `json:"buildDate"`
GoVersion string `json:"goVersion"`
Compiler string `json:"compiler"`
Platform string `json:"platform"`
}
// Get returns the overall codebase version. It's for detecting
// what code a binary was built from.
func Get() Info {
majorVersion, minorVersion := splitVersion(version)
return Info{
Major: majorVersion,
Minor: minorVersion,
GitCommit: gitCommit,
GitVersion: version,
BuildDate: buildDate,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
}
func NewVersionCommand() *cobra.Command {
var versionCmd = &cobra.Command{
Use: "version",
Short: "Version of descheduler",
Long: `Prints the version of descheduler.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Descheduler version %+v\n", Get())
},
}
return versionCmd
}
// splitVersion splits the git version to generate major and minor versions needed.
func splitVersion(version string) (string, string) {
if version == "" {
return "", ""
}
// A sample version would be of form v0.1.0-7-ge884046, so split at first '.' and
// then return 0 and 1+(+ appended to follow semver convention) for major and minor versions.
return strings.Trim(strings.Split(version, ".")[0], "v"), strings.Split(version, ".")[1] + "+"
}

View File

@@ -25,6 +25,7 @@ import (
func main() { func main() {
out := os.Stdout out := os.Stdout
cmd := app.NewDeschedulerCommand(out) cmd := app.NewDeschedulerCommand(out)
cmd.AddCommand(app.NewVersionCommand())
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)

View File

@@ -3,6 +3,8 @@ kind: "DeschedulerPolicy"
strategies: strategies:
"RemoveDuplicates": "RemoveDuplicates":
enabled: true enabled: true
"RemovePodsViolatingInterPodAntiAffinity":
enabled: true
"LowNodeUtilization": "LowNodeUtilization":
enabled: true enabled: true
params: params:

View File

@@ -81,16 +81,16 @@ func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [6]bool var yyq2 [7]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.Kind != "" yyq2[0] = x.Kind != ""
yyq2[1] = x.APIVersion != "" yyq2[1] = x.APIVersion != ""
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(6) r.EncodeArrayStart(7)
} else { } else {
yynn2 = 4 yynn2 = 5
for _, b := range yyq2 { for _, b := range yyq2 {
if b { if b {
yynn2++ yynn2++
@@ -227,6 +227,25 @@ func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
r.EncodeBool(bool(x.DryRun)) r.EncodeBool(bool(x.DryRun))
} }
} }
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.NodeSelector))
}
} else {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("NodeSelector"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.NodeSelector))
}
}
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
@@ -361,6 +380,18 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromMap(l int, d *codec1978.De
*((*bool)(yyv14)) = r.DecodeBool() *((*bool)(yyv14)) = r.DecodeBool()
} }
} }
case "NodeSelector":
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv16 := &x.NodeSelector
yym17 := z.DecBinary()
_ = yym17
if false {
} else {
*((*string)(yyv16)) = r.DecodeString()
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
@@ -372,16 +403,16 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj16 int var yyj18 int
var yyb16 bool var yyb18 bool
var yyhl16 bool = l >= 0 var yyhl18 bool = l >= 0
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -389,29 +420,7 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Kind = "" x.Kind = ""
} else { } else {
yyv17 := &x.Kind yyv19 := &x.Kind
yym18 := z.DecBinary()
_ = yym18
if false {
} else {
*((*string)(yyv17)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv19 := &x.APIVersion
yym20 := z.DecBinary() yym20 := z.DecBinary()
_ = yym20 _ = yym20
if false { if false {
@@ -419,13 +428,35 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
*((*string)(yyv19)) = r.DecodeString() *((*string)(yyv19)) = r.DecodeString()
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv21 := &x.APIVersion
yym22 := z.DecBinary()
_ = yym22
if false {
} else {
*((*string)(yyv21)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -433,22 +464,22 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0 x.DeschedulingInterval = 0
} else { } else {
yyv21 := &x.DeschedulingInterval yyv23 := &x.DeschedulingInterval
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else if z.HasExtensions() && z.DecExt(yyv21) { } else if z.HasExtensions() && z.DecExt(yyv23) {
} else { } else {
*((*int64)(yyv21)) = int64(r.DecodeInt(64)) *((*int64)(yyv23)) = int64(r.DecodeInt(64))
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -456,29 +487,7 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.KubeconfigFile = "" x.KubeconfigFile = ""
} else { } else {
yyv23 := &x.KubeconfigFile yyv25 := &x.KubeconfigFile
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*string)(yyv23)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv25 := &x.PolicyConfigFile
yym26 := z.DecBinary() yym26 := z.DecBinary()
_ = yym26 _ = yym26
if false { if false {
@@ -486,13 +495,35 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
*((*string)(yyv25)) = r.DecodeString() *((*string)(yyv25)) = r.DecodeString()
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv27 := &x.PolicyConfigFile
yym28 := z.DecBinary()
_ = yym28
if false {
} else {
*((*string)(yyv27)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -500,26 +531,48 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.DryRun = false x.DryRun = false
} else { } else {
yyv27 := &x.DryRun yyv29 := &x.DryRun
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*bool)(yyv27)) = r.DecodeBool() *((*bool)(yyv29)) = r.DecodeBool()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv31 := &x.NodeSelector
yym32 := z.DecBinary()
_ = yym32
if false {
} else {
*((*string)(yyv31)) = r.DecodeString()
} }
} }
for { for {
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj16-1, "") z.DecStructFieldNotFound(yyj18-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }

View File

@@ -37,4 +37,7 @@ type DeschedulerConfiguration struct {
// Dry run // Dry run
DryRun bool DryRun bool
// Node selectors
NodeSelector string
} }

View File

@@ -81,7 +81,7 @@ func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
} else { } else {
yysep2 := !z.EncBinary() yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [6]bool var yyq2 [7]bool
_, _, _ = yysep2, yyq2, yy2arr2 _, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false const yyr2 bool = false
yyq2[0] = x.Kind != "" yyq2[0] = x.Kind != ""
@@ -89,9 +89,10 @@ func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[2] = x.DeschedulingInterval != 0 yyq2[2] = x.DeschedulingInterval != 0
yyq2[4] = x.PolicyConfigFile != "" yyq2[4] = x.PolicyConfigFile != ""
yyq2[5] = x.DryRun != false yyq2[5] = x.DryRun != false
yyq2[6] = x.NodeSelector != ""
var yynn2 int var yynn2 int
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
r.EncodeArrayStart(6) r.EncodeArrayStart(7)
} else { } else {
yynn2 = 1 yynn2 = 1
for _, b := range yyq2 { for _, b := range yyq2 {
@@ -248,6 +249,31 @@ func (x *DeschedulerConfiguration) CodecEncodeSelf(e *codec1978.Encoder) {
} }
} }
} }
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[6] {
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.NodeSelector))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[6] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("nodeSelector"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.NodeSelector))
}
}
}
if yyr2 || yy2arr2 { if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234) z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else { } else {
@@ -382,6 +408,18 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromMap(l int, d *codec1978.De
*((*bool)(yyv14)) = r.DecodeBool() *((*bool)(yyv14)) = r.DecodeBool()
} }
} }
case "nodeSelector":
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv16 := &x.NodeSelector
yym17 := z.DecBinary()
_ = yym17
if false {
} else {
*((*string)(yyv16)) = r.DecodeString()
}
}
default: default:
z.DecStructFieldNotFound(-1, yys3) z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3 } // end switch yys3
@@ -393,16 +431,16 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
var h codecSelfer1234 var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d) z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r _, _, _ = h, z, r
var yyj16 int var yyj18 int
var yyb16 bool var yyb18 bool
var yyhl16 bool = l >= 0 var yyhl18 bool = l >= 0
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -410,29 +448,7 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.Kind = "" x.Kind = ""
} else { } else {
yyv17 := &x.Kind yyv19 := &x.Kind
yym18 := z.DecBinary()
_ = yym18
if false {
} else {
*((*string)(yyv17)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv19 := &x.APIVersion
yym20 := z.DecBinary() yym20 := z.DecBinary()
_ = yym20 _ = yym20
if false { if false {
@@ -440,13 +456,35 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
*((*string)(yyv19)) = r.DecodeString() *((*string)(yyv19)) = r.DecodeString()
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
yyv21 := &x.APIVersion
yym22 := z.DecBinary()
_ = yym22
if false {
} else {
*((*string)(yyv21)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -454,22 +492,22 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.DeschedulingInterval = 0 x.DeschedulingInterval = 0
} else { } else {
yyv21 := &x.DeschedulingInterval yyv23 := &x.DeschedulingInterval
yym22 := z.DecBinary() yym24 := z.DecBinary()
_ = yym22 _ = yym24
if false { if false {
} else if z.HasExtensions() && z.DecExt(yyv21) { } else if z.HasExtensions() && z.DecExt(yyv23) {
} else { } else {
*((*int64)(yyv21)) = int64(r.DecodeInt(64)) *((*int64)(yyv23)) = int64(r.DecodeInt(64))
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -477,29 +515,7 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.KubeconfigFile = "" x.KubeconfigFile = ""
} else { } else {
yyv23 := &x.KubeconfigFile yyv25 := &x.KubeconfigFile
yym24 := z.DecBinary()
_ = yym24
if false {
} else {
*((*string)(yyv23)) = r.DecodeString()
}
}
yyj16++
if yyhl16 {
yyb16 = yyj16 > l
} else {
yyb16 = r.CheckBreak()
}
if yyb16 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv25 := &x.PolicyConfigFile
yym26 := z.DecBinary() yym26 := z.DecBinary()
_ = yym26 _ = yym26
if false { if false {
@@ -507,13 +523,35 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
*((*string)(yyv25)) = r.DecodeString() *((*string)(yyv25)) = r.DecodeString()
} }
} }
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.PolicyConfigFile = ""
} else {
yyv27 := &x.PolicyConfigFile
yym28 := z.DecBinary()
_ = yym28
if false {
} else {
*((*string)(yyv27)) = r.DecodeString()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return return
} }
@@ -521,26 +559,48 @@ func (x *DeschedulerConfiguration) codecDecodeSelfFromArray(l int, d *codec1978.
if r.TryDecodeAsNil() { if r.TryDecodeAsNil() {
x.DryRun = false x.DryRun = false
} else { } else {
yyv27 := &x.DryRun yyv29 := &x.DryRun
yym28 := z.DecBinary() yym30 := z.DecBinary()
_ = yym28 _ = yym30
if false { if false {
} else { } else {
*((*bool)(yyv27)) = r.DecodeBool() *((*bool)(yyv29)) = r.DecodeBool()
}
}
yyj18++
if yyhl18 {
yyb18 = yyj18 > l
} else {
yyb18 = r.CheckBreak()
}
if yyb18 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.NodeSelector = ""
} else {
yyv31 := &x.NodeSelector
yym32 := z.DecBinary()
_ = yym32
if false {
} else {
*((*string)(yyv31)) = r.DecodeString()
} }
} }
for { for {
yyj16++ yyj18++
if yyhl16 { if yyhl18 {
yyb16 = yyj16 > l yyb18 = yyj18 > l
} else { } else {
yyb16 = r.CheckBreak() yyb18 = r.CheckBreak()
} }
if yyb16 { if yyb18 {
break break
} }
z.DecSendContainerState(codecSelfer_containerArrayElem1234) z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj16-1, "") z.DecStructFieldNotFound(yyj18-1, "")
} }
z.DecSendContainerState(codecSelfer_containerArrayEnd1234) z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} }

View File

@@ -37,4 +37,7 @@ type DeschedulerConfiguration struct {
// Dry run // Dry run
DryRun bool `json:"dryRun,omitempty"` DryRun bool `json:"dryRun,omitempty"`
// Node selectors
NodeSelector string `json:"nodeSelector,omitempty"`
} }

View File

@@ -45,6 +45,7 @@ func autoConvert_v1alpha1_DeschedulerConfiguration_To_componentconfig_Deschedule
out.KubeconfigFile = in.KubeconfigFile out.KubeconfigFile = in.KubeconfigFile
out.PolicyConfigFile = in.PolicyConfigFile out.PolicyConfigFile = in.PolicyConfigFile
out.DryRun = in.DryRun out.DryRun = in.DryRun
out.NodeSelector = in.NodeSelector
return nil return nil
} }
@@ -58,6 +59,7 @@ func autoConvert_componentconfig_DeschedulerConfiguration_To_v1alpha1_Deschedule
out.KubeconfigFile = in.KubeconfigFile out.KubeconfigFile = in.KubeconfigFile
out.PolicyConfigFile = in.PolicyConfigFile out.PolicyConfigFile = in.PolicyConfigFile
out.DryRun = in.DryRun out.DryRun = in.DryRun
out.NodeSelector = in.NodeSelector
return nil return nil
} }

View File

@@ -19,6 +19,8 @@ package descheduler
import ( import (
"fmt" "fmt"
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options" "github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/client" "github.com/kubernetes-incubator/descheduler/pkg/descheduler/client"
eutils "github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions/utils" eutils "github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions/utils"
@@ -39,22 +41,28 @@ func Run(rs *options.DeschedulerServer) error {
return err return err
} }
if deschedulerPolicy == nil { if deschedulerPolicy == nil {
return fmt.Errorf("\ndeschedulerPolicy is nil\n") return fmt.Errorf("deschedulerPolicy is nil")
} }
evictionPolicyGroupVersion, err := eutils.SupportEviction(rs.Client) evictionPolicyGroupVersion, err := eutils.SupportEviction(rs.Client)
if err != nil || len(evictionPolicyGroupVersion) == 0 { if err != nil || len(evictionPolicyGroupVersion) == 0 {
return err return err
} }
stopChannel := make(chan struct{}) stopChannel := make(chan struct{})
nodes, err := nodeutil.ReadyNodes(rs.Client, stopChannel) nodes, err := nodeutil.ReadyNodes(rs.Client, rs.NodeSelector, stopChannel)
if err != nil { if err != nil {
return err return err
} }
if len(nodes) == 0 {
glog.V(1).Infof("node list is empty")
return nil
}
strategies.RemoveDuplicatePods(rs, deschedulerPolicy.Strategies["RemoveDuplicates"], evictionPolicyGroupVersion, nodes) strategies.RemoveDuplicatePods(rs, deschedulerPolicy.Strategies["RemoveDuplicates"], evictionPolicyGroupVersion, nodes)
strategies.LowNodeUtilization(rs, deschedulerPolicy.Strategies["LowNodeUtilization"], evictionPolicyGroupVersion, nodes) strategies.LowNodeUtilization(rs, deschedulerPolicy.Strategies["LowNodeUtilization"], evictionPolicyGroupVersion, nodes)
strategies.RemovePodsViolatingInterPodAntiAffinity(rs, deschedulerPolicy.Strategies["RemovePodsViolatingInterPodAntiAffinity"], evictionPolicyGroupVersion, nodes)
return nil return nil
} }

View File

@@ -31,20 +31,33 @@ import (
// ReadyNodes returns ready nodes irrespective of whether they are // ReadyNodes returns ready nodes irrespective of whether they are
// schedulable or not. // schedulable or not.
func ReadyNodes(client clientset.Interface, stopChannel <-chan struct{}) ([]*v1.Node, error) { func ReadyNodes(client clientset.Interface, nodeSelector string, stopChannel <-chan struct{}) ([]*v1.Node, error) {
nl := GetNodeLister(client, stopChannel) ns, err := labels.Parse(nodeSelector)
nodes, err := nl.List(labels.Everything())
if err != nil { if err != nil {
return []*v1.Node{}, err return []*v1.Node{}, err
} }
var nodes []*v1.Node
nl := GetNodeLister(client, stopChannel)
if nl != nil {
// err is defined above
if nodes, err = nl.List(ns); err != nil {
return []*v1.Node{}, err
}
}
if len(nodes) == 0 { if len(nodes) == 0 {
var err error glog.V(2).Infof("node lister returned empty list, now fetch directly")
nItems, err := client.Core().Nodes().List(metav1.ListOptions{})
nItems, err := client.Core().Nodes().List(metav1.ListOptions{LabelSelector: nodeSelector})
if err != nil { if err != nil {
return []*v1.Node{}, err return []*v1.Node{}, err
} }
if nItems == nil || len(nItems.Items) == 0 {
return []*v1.Node{}, nil
}
for i := range nItems.Items { for i := range nItems.Items {
node := nItems.Items[i] node := nItems.Items[i]
nodes = append(nodes, &node) nodes = append(nodes, &node)
@@ -61,6 +74,9 @@ func ReadyNodes(client clientset.Interface, stopChannel <-chan struct{}) ([]*v1.
} }
func GetNodeLister(client clientset.Interface, stopChannel <-chan struct{}) corelisters.NodeLister { func GetNodeLister(client clientset.Interface, stopChannel <-chan struct{}) corelisters.NodeLister {
if stopChannel == nil {
return nil
}
listWatcher := cache.NewListWatchFromClient(client.Core().RESTClient(), "nodes", v1.NamespaceAll, fields.Everything()) listWatcher := cache.NewListWatchFromClient(client.Core().RESTClient(), "nodes", v1.NamespaceAll, fields.Everything())
store := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) store := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
nodeLister := corelisters.NewNodeLister(store) nodeLister := corelisters.NewNodeLister(store)

View File

@@ -17,18 +17,14 @@ limitations under the License.
package node package node
import ( import (
"fmt"
"testing" "testing"
"github.com/kubernetes-incubator/descheduler/test" "github.com/kubernetes-incubator/descheduler/test"
"k8s.io/apimachinery/pkg/runtime"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
) )
func TestReadyNodes(t *testing.T) { func TestReadyNodes(t *testing.T) {
fakeClient := &fake.Clientset{}
node1 := test.BuildTestNode("node1", 1000, 2000, 9) node1 := test.BuildTestNode("node1", 1000, 2000, 9)
node1.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}} node1.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeOutOfDisk, Status: v1.ConditionTrue}}
node2 := test.BuildTestNode("node2", 1000, 2000, 9) node2 := test.BuildTestNode("node2", 1000, 2000, 9)
@@ -41,25 +37,6 @@ func TestReadyNodes(t *testing.T) {
node6 := test.BuildTestNode("node6", 1000, 2000, 9) node6 := test.BuildTestNode("node6", 1000, 2000, 9)
node6.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}} node6.Status.Conditions = []v1.NodeCondition{{Type: v1.NodeReady, Status: v1.ConditionFalse}}
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
getAction := action.(core.GetAction)
switch getAction.GetName() {
case node1.Name:
return true, node1, nil
case node2.Name:
return true, node2, nil
case node3.Name:
return true, node3, nil
case node4.Name:
return true, node4, nil
case node5.Name:
return true, node5, nil
case node6.Name:
return true, node6, nil
}
return true, nil, fmt.Errorf("Wrong node: %v", getAction.GetName())
})
if !IsReady(node1) { if !IsReady(node1) {
t.Errorf("Expected %v to be ready", node1.Name) t.Errorf("Expected %v to be ready", node1.Name)
} }
@@ -80,3 +57,18 @@ func TestReadyNodes(t *testing.T) {
} }
} }
func TestReadyNodesWithNodeSelector(t *testing.T) {
node1 := test.BuildTestNode("node1", 1000, 2000, 9)
node1.Labels = map[string]string{"type": "compute"}
node2 := test.BuildTestNode("node2", 1000, 2000, 9)
node2.Labels = map[string]string{"type": "infra"}
fakeClient := fake.NewSimpleClientset(node1, node2)
nodeSelector := "type=compute"
nodes, _ := ReadyNodes(fakeClient, nodeSelector, nil)
if nodes[0].Name != "node1" {
t.Errorf("Expected node1, got %s", nodes[0].Name)
}
}

View File

@@ -0,0 +1,102 @@
/*
Copyright 2017 The Kubernetes 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 strategies
import (
"github.com/kubernetes-incubator/descheduler/cmd/descheduler/app/options"
"github.com/kubernetes-incubator/descheduler/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
"github.com/golang/glog"
"github.com/kubernetes-incubator/descheduler/pkg/descheduler/evictions"
podutil "github.com/kubernetes-incubator/descheduler/pkg/descheduler/pod"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
//TODO: Change to client-go instead of generated clientset.
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
priorityutil "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/priorities/util"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
)
// RemovePodsViolatingInterPodAntiAffinity with elimination strategy
func RemovePodsViolatingInterPodAntiAffinity(ds *options.DeschedulerServer, strategy api.DeschedulerStrategy, policyGroupVersion string, nodes []*v1.Node) {
if !strategy.Enabled {
return
}
removePodsWithAffinityRules(ds.Client, policyGroupVersion, nodes, ds.DryRun)
}
// removePodsWithAffinityRules evicts pods on the node which are having a pod affinity rules.
func removePodsWithAffinityRules(client clientset.Interface, policyGroupVersion string, nodes []*v1.Node, dryRun bool) int {
podsEvicted := 0
for _, node := range nodes {
glog.V(1).Infof("Processing node: %#v\n", node.Name)
pods, err := podutil.ListPodsOnANode(client, node)
if err != nil {
return 0
}
totalPods := len(pods)
for i := 0; i < totalPods; i++ {
if checkPodsWithAntiAffinityExist(pods[i], pods) {
success, err := evictions.EvictPod(client, pods[i], policyGroupVersion, dryRun)
if !success {
glog.Infof("Error when evicting pod: %#v (%#v)\n", pods[i].Name, err)
} else {
podsEvicted++
glog.V(1).Infof("Evicted pod: %#v (%#v)\n because of existing anti-affinity", pods[i].Name, err)
// Since the current pod is evicted all other pods which have anti-affinity with this
// pod need not be evicted.
// Update pods.
pods = append(pods[:i], pods[i+1:]...)
i--
totalPods--
}
}
}
}
return podsEvicted
}
// checkPodsWithAntiAffinityExist checks if there are other pods on the node that the current pod cannot tolerate.
func checkPodsWithAntiAffinityExist(pod *v1.Pod, pods []*v1.Pod) bool {
affinity := schedulercache.ReconcileAffinity(pod)
if affinity != nil && affinity.PodAntiAffinity != nil {
for _, term := range getPodAntiAffinityTerms(affinity.PodAntiAffinity) {
namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(pod, &term)
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
if err != nil {
glog.Infof("%v", err)
return false
}
for _, existingPod := range pods {
if existingPod.Name != pod.Name && priorityutil.PodMatchesTermsNamespaceAndSelector(existingPod, namespaces, selector) {
return true
}
}
}
}
return false
}
// getPodAntiAffinityTerms gets the antiaffinity terms for the given pod.
func getPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.PodAffinityTerm) {
if podAntiAffinity != nil {
if len(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
terms = podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution
}
}
return terms
}

View File

@@ -0,0 +1,86 @@
/*
Copyright 2017 The Kubernetes 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 strategies
import (
"testing"
"fmt"
"github.com/kubernetes-incubator/descheduler/test"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
core "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
)
func TestPodAntiAffinity(t *testing.T) {
node := test.BuildTestNode("n1", 2000, 3000, 10)
p1 := test.BuildTestPod("p1", 100, 0, node.Name)
p2 := test.BuildTestPod("p2", 100, 0, node.Name)
p3 := test.BuildTestPod("p3", 100, 0, node.Name)
p3.Labels = map[string]string{"foo": "bar"}
p1.Spec.Affinity = &v1.Affinity{
PodAntiAffinity: &v1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "foo",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"bar"},
},
},
},
TopologyKey: "region",
},
},
},
}
p3.Spec.Affinity = &v1.Affinity{
PodAntiAffinity: &v1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
{
LabelSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "foo",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"bar"},
},
},
},
TopologyKey: "region",
},
},
},
}
fakeClient := &fake.Clientset{}
fakeClient.Fake.AddReactor("list", "pods", func(action core.Action) (bool, runtime.Object, error) {
return true, &v1.PodList{Items: []v1.Pod{*p1, *p2, *p3}}, nil
})
fakeClient.Fake.AddReactor("get", "nodes", func(action core.Action) (bool, runtime.Object, error) {
return true, node, nil
})
expectedEvictedPodCount := 1
podsEvicted := removePodsWithAffinityRules(fakeClient, "v1", []*v1.Node{node}, false)
if podsEvicted != expectedEvictedPodCount {
fmt.Println(podsEvicted)
t.Errorf("Unexpected no of pods evicted")
}
}