diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 000000000..a392ba08f --- /dev/null +++ b/.licenseignore @@ -0,0 +1,2 @@ +vendor +pkg/descheduler diff --git a/go.mod b/go.mod index 860a45496..ba8e11f38 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( k8s.io/kubernetes v1.22.6 k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a sigs.k8s.io/controller-runtime v0.10.3 + sigs.k8s.io/yaml v1.2.0 ) require ( @@ -140,7 +141,6 @@ require ( k8s.io/mount-utils v0.22.6 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect ) replace ( diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 9a195646d..ca7d77ceb 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -60,6 +60,15 @@ ${SCRIPT_ROOT}/hack/generate-internal-groups.sh \ --output-base "${TEMP_DIR}" \ --go-header-file hack/boilerplate/boilerplate.go.txt +${SCRIPT_ROOT}/hack/generate-internal-groups.sh \ + "deepcopy,conversion,defaulter" \ + github.com/koordinator-sh/koordinator/pkg/descheduler/apis/generated \ + github.com/koordinator-sh/koordinator/pkg/descheduler/apis \ + github.com/koordinator-sh/koordinator/pkg/descheduler/apis \ + "config:v1alpha2" \ + --output-base "${TEMP_DIR}" \ + --go-header-file hack/boilerplate/boilerplate.go.txt + # Copy everything back. cp -a "${TEMP_DIR}/${ROOT_PKG}/." "${SCRIPT_ROOT}/" diff --git a/hack/update-license-header.sh b/hack/update-license-header.sh index c09ec3cee..1ca9a52f7 100755 --- a/hack/update-license-header.sh +++ b/hack/update-license-header.sh @@ -21,4 +21,6 @@ LICENSEHEADERCHECKER_VERSION=v1.3.0 GOBIN=${PROJECT}/bin go install github.com/lsm-dev/license-header-checker/cmd/license-header-checker@${LICENSEHEADERCHECKER_VERSION} -${PROJECT}/bin/license-header-checker -r -a -v -i vendor ${PROJECT}/hack/boilerplate/boilerplate.go.txt . go +LICENSEIGNORE=$(cat ${PROJECT}/.licenseignore | tr '\n' ',') + +${PROJECT}/bin/license-header-checker -r -a -v -i ${LICENSEIGNORE} ${PROJECT}/hack/boilerplate/boilerplate.go.txt . go diff --git a/pkg/descheduler/apis/config/doc.go b/pkg/descheduler/apis/config/doc.go new file mode 100644 index 000000000..7f7486303 --- /dev/null +++ b/pkg/descheduler/apis/config/doc.go @@ -0,0 +1,20 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=descheduler + +package config diff --git a/pkg/descheduler/apis/config/register.go b/pkg/descheduler/apis/config/register.go new file mode 100644 index 000000000..cea2e1afa --- /dev/null +++ b/pkg/descheduler/apis/config/register.go @@ -0,0 +1,53 @@ +/* +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 config + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme + Scheme = runtime.NewScheme() +) + +// GroupName is the group name use in this package +const GroupName = "descheduler" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &DeschedulerConfiguration{}, + &DefaultEvictorArgs{}, + &RemovePodsViolatingNodeAffinityArgs{}, + ) + return nil +} diff --git a/pkg/descheduler/apis/config/scheme/scheme.go b/pkg/descheduler/apis/config/scheme/scheme.go new file mode 100644 index 000000000..d3b0686cc --- /dev/null +++ b/pkg/descheduler/apis/config/scheme/scheme.go @@ -0,0 +1,44 @@ +/* +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 scheme + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" + "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config/v1alpha2" +) + +var ( + // Scheme is the runtime.Scheme to which all koord-descheduler api types are registered. + Scheme = runtime.NewScheme() + + // Codecs provides access to encoding and decoding for the scheme. + Codecs = serializer.NewCodecFactory(Scheme, serializer.EnableStrict) +) + +func init() { + AddToScheme(Scheme) +} + +// AddToScheme builds the koord-descheduler scheme using all known versions of the koord-descheduler api. +func AddToScheme(scheme *runtime.Scheme) { + utilruntime.Must(config.AddToScheme(scheme)) + utilruntime.Must(v1alpha2.AddToScheme(scheme)) +} diff --git a/pkg/descheduler/apis/config/types.go b/pkg/descheduler/apis/config/types.go new file mode 100644 index 000000000..381c3eaa1 --- /dev/null +++ b/pkg/descheduler/apis/config/types.go @@ -0,0 +1,91 @@ +/* +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 config + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/component-base/config" +) + +const ( + DefaultDeschedulerPort = 10258 + DefaultInsecureDeschedulerPort = 10251 +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DeschedulerConfiguration configures a descheduler +type DeschedulerConfiguration struct { + metav1.TypeMeta + + // LeaderElection defines the configuration of leader election client. + LeaderElection config.LeaderElectionConfiguration + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection config.ClientConnectionConfiguration + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfig.DebuggingConfiguration + config.DebuggingConfiguration + + // HealthzBindAddress is the IP address and port for the health check server to serve on. + HealthzBindAddress string + // MetricsBindAddress is the IP address and port for the metrics server to serve on. + MetricsBindAddress string + + // Time interval for descheduler to run + DeschedulingInterval metav1.Duration + + // Dry run + DryRun bool + + // Profiles are descheduling profiles that koord-descheduler supports. + Profiles []DeschedulerProfile + + // NodeSelector for a set of nodes to operate over + NodeSelector *metav1.LabelSelector +} + +// DeschedulerProfile is a descheduling profile. +type DeschedulerProfile struct { + Name string + PluginConfig []PluginConfig + Plugins *Plugins +} + +type Plugins struct { + Deschedule PluginSet + Balance PluginSet + Evictor PluginSet +} + +type PluginSet struct { + Enabled []Plugin + Disabled []Plugin +} + +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name"` +} + +type PluginConfig struct { + Name string + Args runtime.Object +} diff --git a/pkg/descheduler/apis/config/types_pluginargs.go b/pkg/descheduler/apis/config/types_pluginargs.go new file mode 100644 index 000000000..a39bcb4a8 --- /dev/null +++ b/pkg/descheduler/apis/config/types_pluginargs.go @@ -0,0 +1,81 @@ +/* +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 config + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultEvictorArgs holds arguments used to configure the DefaultEvictor plugin. +type DefaultEvictorArgs struct { + metav1.TypeMeta + + DryRun bool + // MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node. + MaxNoOfPodsToEvictPerNode *int + // MaxNoOfPodsToEvictPerNamespace restricts maximum of pods to be evicted per namespace. + MaxNoOfPodsToEvictPerNamespace *int + + // EvictFailedBarePods allows pods without ownerReferences and in failed phase to be evicted. + EvictFailedBarePods bool + + // EvictLocalStoragePods allows pods using local storage to be evicted. + EvictLocalStoragePods bool + + // EvictSystemCriticalPods allows eviction of pods of any priority (including Kubernetes system pods) + EvictSystemCriticalPods bool + + // IgnorePVCPods prevents pods with PVCs from being evicted. + IgnorePvcPods bool + + // NodeFit sets whether to consider taints, node selectors, + // and pod affinity when evicting. A pod whose tolerations, node selectors, + // and affinity match a node other than the one it is currently running on + // is evictable. + NodeFit bool + // PriorityThreshold represents a threshold for pod's priority class. + // Any pod whose priority class is lower is evictable. + PriorityThreshold *PriorityThreshold + // LabelSelector sets whether to apply label filtering when evicting. + // Any pod matching the label selector is considered evictable. + LabelSelector *metav1.LabelSelector +} + +type PriorityThreshold struct { + Value *int32 + Name string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure the RemovePodsViolatingNodeAffinity plugin. +type RemovePodsViolatingNodeAffinityArgs struct { + metav1.TypeMeta + + Namespaces *Namespaces + LabelSelector *metav1.LabelSelector + NodeAffinityType []string +} + +// Namespaces carries a list of included/excluded namespaces +// for which a given strategy is applicable +type Namespaces struct { + Include []string + Exclude []string +} diff --git a/pkg/descheduler/apis/config/v1alpha2/conversion.go b/pkg/descheduler/apis/config/v1alpha2/conversion.go new file mode 100644 index 000000000..ba41c17cc --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/conversion.go @@ -0,0 +1,107 @@ +/* +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 v1alpha2 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1alpha2 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(config.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1alpha2_DeschedulerConfiguration_To_config_DeschedulerConfiguration(in *DeschedulerConfiguration, out *config.DeschedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_v1alpha2_DeschedulerConfiguration_To_config_DeschedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *config.DeschedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfig { + args := prof.PluginConfig[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err) + } + prof.PluginConfig[j].Args = internalArgs + } + } + return nil +} + +func Convert_config_DeschedulerConfiguration_To_v1alpha2_DeschedulerConfiguration(in *config.DeschedulerConfiguration, out *DeschedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_config_DeschedulerConfiguration_To_v1alpha2_DeschedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *DeschedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfig { + args := out.Profiles[i].PluginConfig[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfig[j].Args.Object = externalArgs + } + } + return nil +} diff --git a/pkg/descheduler/apis/config/v1alpha2/default_plugins.go b/pkg/descheduler/apis/config/v1alpha2/default_plugins.go new file mode 100644 index 000000000..580ccfc81 --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/default_plugins.go @@ -0,0 +1,84 @@ +/* +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 v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" +) + +// getDefaultPlugins returns the default set of plugins. +func getDefaultPlugins() *Plugins { + plugins := &Plugins{} + return plugins +} + +// mergePlugins merges the custom set into the given default one, handling disabled sets. +func mergePlugins(defaultPlugins, customPlugins *Plugins) *Plugins { + if customPlugins == nil { + return defaultPlugins + } + + defaultPlugins.Deschedule = mergePluginSet(defaultPlugins.Deschedule, customPlugins.Deschedule) + defaultPlugins.Balance = mergePluginSet(defaultPlugins.Balance, customPlugins.Balance) + defaultPlugins.Evictor = mergePluginSet(defaultPlugins.Evictor, customPlugins.Evictor) + return defaultPlugins +} + +type pluginIndex struct { + index int + plugin Plugin +} + +func mergePluginSet(defaultPluginSet, customPluginSet PluginSet) PluginSet { + disabledPlugins := sets.NewString() + enabledCustomPlugins := make(map[string]pluginIndex) + // replacedPluginIndex is a set of index of plugins, which have replaced the default plugins. + replacedPluginIndex := sets.NewInt() + for _, disabledPlugin := range customPluginSet.Disabled { + disabledPlugins.Insert(disabledPlugin.Name) + } + for index, enabledPlugin := range customPluginSet.Enabled { + enabledCustomPlugins[enabledPlugin.Name] = pluginIndex{index, enabledPlugin} + } + var enabledPlugins []Plugin + if !disabledPlugins.Has("*") { + for _, defaultEnabledPlugin := range defaultPluginSet.Enabled { + if disabledPlugins.Has(defaultEnabledPlugin.Name) { + continue + } + // The default plugin is explicitly re-configured, update the default plugin accordingly. + if customPlugin, ok := enabledCustomPlugins[defaultEnabledPlugin.Name]; ok { + klog.InfoS("Default plugin is explicitly re-configured; overriding", "plugin", defaultEnabledPlugin.Name) + // Update the default plugin in place to preserve order. + defaultEnabledPlugin = customPlugin.plugin + replacedPluginIndex.Insert(customPlugin.index) + } + enabledPlugins = append(enabledPlugins, defaultEnabledPlugin) + } + } + + // Append all the custom plugins which haven't replaced any default plugins. + // Note: duplicated custom plugins will still be appended here. + // If so, the instantiation of descheduler framework will detect it and abort. + for index, plugin := range customPluginSet.Enabled { + if !replacedPluginIndex.Has(index) { + enabledPlugins = append(enabledPlugins, plugin) + } + } + return PluginSet{Enabled: enabledPlugins} +} diff --git a/pkg/descheduler/apis/config/v1alpha2/defaults.go b/pkg/descheduler/apis/config/v1alpha2/defaults.go new file mode 100644 index 000000000..fcadf6314 --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/defaults.go @@ -0,0 +1,191 @@ +/* +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 v1alpha2 + +import ( + "net" + "strconv" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "k8s.io/utils/pointer" + + "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" +) + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func pluginsNames(p *Plugins) []string { + if p == nil { + return nil + } + extensions := []PluginSet{ + p.Deschedule, + p.Balance, + p.Evictor, + } + n := sets.NewString() + for _, e := range extensions { + for _, pg := range e.Enabled { + n.Insert(pg.Name) + } + } + return n.List() +} + +func setDefaults_Profile(prof *DeschedulerProfile) { + // Set default plugins. + prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins) + + // Set default plugin configs. + scheme := GetPluginArgConversionScheme() + existingConfigs := sets.NewString() + for j := range prof.PluginConfig { + existingConfigs.Insert(prof.PluginConfig[j].Name) + args := prof.PluginConfig[j].Args.Object + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + scheme.Default(args) + } + + // Append default configs for plugins that didn't have one explicitly set. + for _, name := range pluginsNames(prof.Plugins) { + if existingConfigs.Has(name) { + continue + } + gvk := SchemeGroupVersion.WithKind(name + "Args") + args, err := scheme.New(gvk) + if err != nil { + // This plugin is out-of-tree or doesn't require configuration. + continue + } + scheme.Default(args) + args.GetObjectKind().SetGroupVersionKind(gvk) + prof.PluginConfig = append(prof.PluginConfig, PluginConfig{ + Name: name, + Args: runtime.RawExtension{Object: args}, + }) + } +} + +// SetDefaults_DeschedulerConfiguration sets additional defaults +func SetDefaults_DeschedulerConfiguration(obj *DeschedulerConfiguration) { + if len(obj.Profiles) == 0 { + obj.Profiles = append(obj.Profiles, DeschedulerProfile{}) + } + // Only apply a default scheduler name when there is a single profile. + // Validation will ensure that every profile has a non-empty unique name. + if len(obj.Profiles) == 1 && obj.Profiles[0].Name == "" { + obj.Profiles[0].Name = "koord-descheduler" + } + + // Add the default set of plugins and apply the configuration. + for i := range obj.Profiles { + prof := &obj.Profiles[i] + setDefaults_Profile(prof) + } + + if len(obj.LeaderElection.ResourceLock) == 0 { + // Use lease-based leader election to reduce cost. + // We migrated for EndpointsLease lock in 1.17 and starting in 1.20 we + // migrated to Lease lock. + obj.LeaderElection.ResourceLock = "leases" + } + if len(obj.LeaderElection.ResourceNamespace) == 0 { + obj.LeaderElection.ResourceNamespace = "koordinator-system" + } + if len(obj.LeaderElection.ResourceName) == 0 { + obj.LeaderElection.ResourceName = "koord-descheduler" + } + // Use the default LeaderElectionConfiguration options + componentbaseconfigv1alpha1.RecommendedDefaultLeaderElectionConfiguration(&obj.LeaderElection) + + if len(obj.ClientConnection.ContentType) == 0 { + obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf" + } + // Scheduler has an opinion about QPS/Burst, setting specific defaults for itself, instead of generic settings. + if obj.ClientConnection.QPS == 0.0 { + obj.ClientConnection.QPS = 50.0 + } + if obj.ClientConnection.Burst == 0 { + obj.ClientConnection.Burst = 100 + } + + // Enable profiling by default in the scheduler + if obj.EnableProfiling == nil { + enableProfiling := true + obj.EnableProfiling = &enableProfiling + } + + // Enable contention profiling by default if profiling is enabled + if *obj.EnableProfiling && obj.EnableContentionProfiling == nil { + enableContentionProfiling := true + obj.EnableContentionProfiling = &enableContentionProfiling + } + + defaultBindAddress := net.JoinHostPort("0.0.0.0", strconv.Itoa(config.DefaultDeschedulerPort)) + if obj.HealthzBindAddress == nil { + obj.HealthzBindAddress = &defaultBindAddress + } else { + if host, port, err := net.SplitHostPort(*obj.HealthzBindAddress); err == nil { + if len(host) == 0 { + host = "0.0.0.0" + } + hostPort := net.JoinHostPort(host, port) + obj.HealthzBindAddress = &hostPort + } else { + if host := net.ParseIP(*obj.HealthzBindAddress); host != nil { + hostPort := net.JoinHostPort(*obj.HealthzBindAddress, strconv.Itoa(config.DefaultDeschedulerPort)) + obj.HealthzBindAddress = &hostPort + } + } + } + + if obj.MetricsBindAddress == nil { + obj.MetricsBindAddress = &defaultBindAddress + } else { + if host, port, err := net.SplitHostPort(*obj.MetricsBindAddress); err == nil { + if len(host) == 0 { + host = "0.0.0.0" + } + hostPort := net.JoinHostPort(host, port) + obj.MetricsBindAddress = &hostPort + } else { + if host := net.ParseIP(*obj.MetricsBindAddress); host != nil { + hostPort := net.JoinHostPort(*obj.MetricsBindAddress, strconv.Itoa(config.DefaultDeschedulerPort)) + obj.MetricsBindAddress = &hostPort + } + } + } +} + +func SetDefaults_DefaultEvictorArgs(obj *DefaultEvictorArgs) { + // TODO(joseph): the current version disables the eviction ability by default + if obj.DryRun == nil { + obj.DryRun = pointer.Bool(true) + } +} + +func SetDefaults_RemovePodsViolatingNodeAffinityArgs(obj *RemovePodsViolatingNodeAffinityArgs) { + if len(obj.NodeAffinityType) == 0 { + obj.NodeAffinityType = append(obj.NodeAffinityType, "requiredDuringSchedulingIgnoredDuringExecution") + } +} diff --git a/pkg/descheduler/apis/config/v1alpha2/doc.go b/pkg/descheduler/apis/config/v1alpha2/doc.go new file mode 100644 index 000000000..bbc06a6c6 --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/doc.go @@ -0,0 +1,25 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config +// +k8s:conversion-gen=k8s.io/component-base/config/v1alpha1 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=. +// +groupName=descheduler + +// Package v1alpha2 is the v1alpha2 version of the descheduler API +package v1alpha2 diff --git a/pkg/descheduler/apis/config/v1alpha2/register.go b/pkg/descheduler/apis/config/v1alpha2/register.go new file mode 100644 index 000000000..20e5b19f9 --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/register.go @@ -0,0 +1,62 @@ +/* +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 v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + localSchemeBuilder = &SchemeBuilder + AddToScheme = SchemeBuilder.AddToScheme +) + +// GroupName is the group name used in this package +const GroupName = "descheduler" +const GroupVersion = "v1alpha2" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs) +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &DeschedulerConfiguration{}, + &DefaultEvictorArgs{}, + &RemovePodsViolatingNodeAffinityArgs{}, + ) + + return nil +} diff --git a/pkg/descheduler/apis/config/v1alpha2/types.go b/pkg/descheduler/apis/config/v1alpha2/types.go new file mode 100644 index 000000000..8cc5173f6 --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/types.go @@ -0,0 +1,158 @@ +/* +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 v1alpha2 + +import ( + "bytes" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/component-base/config/v1alpha1" + "sigs.k8s.io/yaml" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DeschedulerConfiguration configures a descheduler +type DeschedulerConfiguration struct { + metav1.TypeMeta + + // LeaderElection defines the configuration of leader election client. + LeaderElection v1alpha1.LeaderElectionConfiguration `json:"leaderElection"` + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection v1alpha1.ClientConnectionConfiguration `json:"clientConnection"` + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration + v1alpha1.DebuggingConfiguration `json:",inline"` + + // Note: Both HealthzBindAddress and MetricsBindAddress fields are deprecated. + // Only empty address or port 0 is allowed. Anything else will fail validation. + // HealthzBindAddress is the IP address and port for the health check server to serve on. + HealthzBindAddress *string `json:"healthzBindAddress,omitempty"` + // MetricsBindAddress is the IP address and port for the metrics server to serve on. + MetricsBindAddress *string `json:"metricsBindAddress,omitempty"` + + // Time interval for descheduler to run + DeschedulingInterval metav1.Duration `json:"deschedulingInterval,omitempty"` + + // Dry run + DryRun bool `json:"dryRun,omitempty"` + + // Profiles + Profiles []DeschedulerProfile `json:"profiles,omitempty"` + + // NodeSelector for a set of nodes to operate over + NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"` +} + +// DecodeNestedObjects decodes plugin args for known types. +func (c *DeschedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].decodeNestedObjects(d) + if err != nil { + return fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// EncodeNestedObjects encodes plugin args. +func (c *DeschedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].encodeNestedObjects(e) + if err != nil { + return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// DeschedulerProfile is a descheduling profile. +type DeschedulerProfile struct { + Name string `json:"name,omitempty"` + PluginConfig []PluginConfig `json:"pluginConfig,omitempty"` + Plugins *Plugins `json:"plugins,omitempty"` +} + +type Plugins struct { + Deschedule PluginSet `json:"deschedule,omitempty"` + Balance PluginSet `json:"balance,omitempty"` + Evictor PluginSet `json:"evict,omitempty"` +} + +type PluginSet struct { + Enabled []Plugin `json:"enabled,omitempty"` + Disabled []Plugin `json:"disabled,omitempty"` +} + +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name,omitempty"` +} + +type PluginConfig struct { + Name string `json:"name"` + Args runtime.RawExtension `json:"args,omitempty"` +} + +func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error { + gvk := SchemeGroupVersion.WithKind(c.Name + "Args") + // dry-run to detect and skip out-of-tree plugin args. + if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) { + return nil + } + + obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil) + if err != nil { + return fmt.Errorf("decoding args for plugin %s: %w", c.Name, err) + } + if parsedGvk.GroupKind() != gvk.GroupKind() { + return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind()) + } + c.Args.Object = obj + return nil +} + +func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error { + if c.Args.Object == nil { + return nil + } + var buf bytes.Buffer + err := e.Encode(c.Args.Object, &buf) + if err != nil { + return err + } + // The encoder might be a YAML encoder, but the parent encoder expects + // JSON output, so we convert YAML back to JSON. + // This is a no-op if produces JSON. + json, err := yaml.YAMLToJSON(buf.Bytes()) + if err != nil { + return err + } + c.Args.Raw = json + return nil +} diff --git a/pkg/descheduler/apis/config/v1alpha2/types_pluginargs.go b/pkg/descheduler/apis/config/v1alpha2/types_pluginargs.go new file mode 100644 index 000000000..fd1043c5b --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/types_pluginargs.go @@ -0,0 +1,81 @@ +/* +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 v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultEvictorArgs holds arguments used to configure the DefaultEvictor plugin. +type DefaultEvictorArgs struct { + metav1.TypeMeta + + DryRun *bool `json:"dryRun,omitempty"` + // MaxNoOfPodsToEvictPerNode restricts maximum of pods to be evicted per node. + MaxNoOfPodsToEvictPerNode *int `json:"maxNoOfPodsToEvictPerNode,omitempty"` + // MaxNoOfPodsToEvictPerNamespace restricts maximum of pods to be evicted per namespace. + MaxNoOfPodsToEvictPerNamespace *int `json:"maxNoOfPodsToEvictPerNamespace,omitempty"` + + // EvictFailedBarePods allows pods without ownerReferences and in failed phase to be evicted. + EvictFailedBarePods bool `json:"evictFailedBarePods"` + + // EvictLocalStoragePods allows pods using local storage to be evicted. + EvictLocalStoragePods bool `json:"evictLocalStoragePods"` + + // EvictSystemCriticalPods allows eviction of pods of any priority (including Kubernetes system pods) + EvictSystemCriticalPods bool `json:"evictSystemCriticalPods"` + + // IgnorePVCPods prevents pods with PVCs from being evicted. + IgnorePvcPods bool `json:"ignorePvcPods"` + + // NodeFit sets whether to consider taints, node selectors, + // and pod affinity when evicting. A pod whose tolerations, node selectors, + // and affinity match a node other than the one it is currently running on + // is evictable. + NodeFit bool `json:"nodeFit"` + // PriorityThreshold represents a threshold for pod's priority class. + // Any pod whose priority class is lower is evictable. + PriorityThreshold *PriorityThreshold `json:"priorityThreshold,omitempty"` + // LabelSelector sets whether to apply label filtering when evicting. + // Any pod matching the label selector is considered evictable. + LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"` +} + +type PriorityThreshold struct { + Value *int32 `json:"value,omitempty"` + Name string `json:"name,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RemovePodsViolatingNodeAffinityArgs holds arguments used to configure the RemovePodsViolatingNodeAffinity plugin. +type RemovePodsViolatingNodeAffinityArgs struct { + metav1.TypeMeta + + Namespaces *Namespaces `json:"namespaces,omitempty"` + LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"` + NodeAffinityType []string `json:"nodeAffinityType,omitempty"` +} + +// Namespaces carries a list of included/excluded namespaces +// for which a given strategy is applicable +type Namespaces struct { + Include []string `json:"include,omitempty"` + Exclude []string `json:"exclude,omitempty"` +} diff --git a/pkg/descheduler/apis/config/v1alpha2/zz_generated.conversion.go b/pkg/descheduler/apis/config/v1alpha2/zz_generated.conversion.go new file mode 100644 index 000000000..9040db64b --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/zz_generated.conversion.go @@ -0,0 +1,466 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + unsafe "unsafe" + + config "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + v1alpha1 "k8s.io/component-base/config/v1alpha1" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*DefaultEvictorArgs)(nil), (*config.DefaultEvictorArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_DefaultEvictorArgs_To_config_DefaultEvictorArgs(a.(*DefaultEvictorArgs), b.(*config.DefaultEvictorArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DefaultEvictorArgs)(nil), (*DefaultEvictorArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DefaultEvictorArgs_To_v1alpha2_DefaultEvictorArgs(a.(*config.DefaultEvictorArgs), b.(*DefaultEvictorArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*DeschedulerProfile)(nil), (*config.DeschedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile(a.(*DeschedulerProfile), b.(*config.DeschedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DeschedulerProfile)(nil), (*DeschedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile(a.(*config.DeschedulerProfile), b.(*DeschedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Namespaces)(nil), (*config.Namespaces)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Namespaces_To_config_Namespaces(a.(*Namespaces), b.(*config.Namespaces), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Namespaces)(nil), (*Namespaces)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Namespaces_To_v1alpha2_Namespaces(a.(*config.Namespaces), b.(*Namespaces), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Plugin_To_config_Plugin(a.(*Plugin), b.(*config.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugin)(nil), (*Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugin_To_v1alpha2_Plugin(a.(*config.Plugin), b.(*Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PluginConfig)(nil), (*config.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PluginConfig_To_config_PluginConfig(a.(*PluginConfig), b.(*config.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginConfig)(nil), (*PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginConfig_To_v1alpha2_PluginConfig(a.(*config.PluginConfig), b.(*PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PluginSet)(nil), (*config.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PluginSet_To_config_PluginSet(a.(*PluginSet), b.(*config.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginSet)(nil), (*PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginSet_To_v1alpha2_PluginSet(a.(*config.PluginSet), b.(*PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Plugins)(nil), (*config.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_Plugins_To_config_Plugins(a.(*Plugins), b.(*config.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugins)(nil), (*Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugins_To_v1alpha2_Plugins(a.(*config.Plugins), b.(*Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*PriorityThreshold)(nil), (*config.PriorityThreshold)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PriorityThreshold_To_config_PriorityThreshold(a.(*PriorityThreshold), b.(*config.PriorityThreshold), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PriorityThreshold)(nil), (*PriorityThreshold)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PriorityThreshold_To_v1alpha2_PriorityThreshold(a.(*config.PriorityThreshold), b.(*PriorityThreshold), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*RemovePodsViolatingNodeAffinityArgs)(nil), (*config.RemovePodsViolatingNodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_RemovePodsViolatingNodeAffinityArgs_To_config_RemovePodsViolatingNodeAffinityArgs(a.(*RemovePodsViolatingNodeAffinityArgs), b.(*config.RemovePodsViolatingNodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RemovePodsViolatingNodeAffinityArgs)(nil), (*RemovePodsViolatingNodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RemovePodsViolatingNodeAffinityArgs_To_v1alpha2_RemovePodsViolatingNodeAffinityArgs(a.(*config.RemovePodsViolatingNodeAffinityArgs), b.(*RemovePodsViolatingNodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.DeschedulerConfiguration)(nil), (*DeschedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DeschedulerConfiguration_To_v1alpha2_DeschedulerConfiguration(a.(*config.DeschedulerConfiguration), b.(*DeschedulerConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*DeschedulerConfiguration)(nil), (*config.DeschedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_DeschedulerConfiguration_To_config_DeschedulerConfiguration(a.(*DeschedulerConfiguration), b.(*config.DeschedulerConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha2_DefaultEvictorArgs_To_config_DefaultEvictorArgs(in *DefaultEvictorArgs, out *config.DefaultEvictorArgs, s conversion.Scope) error { + if err := v1.Convert_Pointer_bool_To_bool(&in.DryRun, &out.DryRun, s); err != nil { + return err + } + out.MaxNoOfPodsToEvictPerNode = (*int)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNode)) + out.MaxNoOfPodsToEvictPerNamespace = (*int)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNamespace)) + out.EvictFailedBarePods = in.EvictFailedBarePods + out.EvictLocalStoragePods = in.EvictLocalStoragePods + out.EvictSystemCriticalPods = in.EvictSystemCriticalPods + out.IgnorePvcPods = in.IgnorePvcPods + out.NodeFit = in.NodeFit + out.PriorityThreshold = (*config.PriorityThreshold)(unsafe.Pointer(in.PriorityThreshold)) + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + return nil +} + +// Convert_v1alpha2_DefaultEvictorArgs_To_config_DefaultEvictorArgs is an autogenerated conversion function. +func Convert_v1alpha2_DefaultEvictorArgs_To_config_DefaultEvictorArgs(in *DefaultEvictorArgs, out *config.DefaultEvictorArgs, s conversion.Scope) error { + return autoConvert_v1alpha2_DefaultEvictorArgs_To_config_DefaultEvictorArgs(in, out, s) +} + +func autoConvert_config_DefaultEvictorArgs_To_v1alpha2_DefaultEvictorArgs(in *config.DefaultEvictorArgs, out *DefaultEvictorArgs, s conversion.Scope) error { + if err := v1.Convert_bool_To_Pointer_bool(&in.DryRun, &out.DryRun, s); err != nil { + return err + } + out.MaxNoOfPodsToEvictPerNode = (*int)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNode)) + out.MaxNoOfPodsToEvictPerNamespace = (*int)(unsafe.Pointer(in.MaxNoOfPodsToEvictPerNamespace)) + out.EvictFailedBarePods = in.EvictFailedBarePods + out.EvictLocalStoragePods = in.EvictLocalStoragePods + out.EvictSystemCriticalPods = in.EvictSystemCriticalPods + out.IgnorePvcPods = in.IgnorePvcPods + out.NodeFit = in.NodeFit + out.PriorityThreshold = (*PriorityThreshold)(unsafe.Pointer(in.PriorityThreshold)) + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + return nil +} + +// Convert_config_DefaultEvictorArgs_To_v1alpha2_DefaultEvictorArgs is an autogenerated conversion function. +func Convert_config_DefaultEvictorArgs_To_v1alpha2_DefaultEvictorArgs(in *config.DefaultEvictorArgs, out *DefaultEvictorArgs, s conversion.Scope) error { + return autoConvert_config_DefaultEvictorArgs_To_v1alpha2_DefaultEvictorArgs(in, out, s) +} + +func autoConvert_v1alpha2_DeschedulerConfiguration_To_config_DeschedulerConfiguration(in *DeschedulerConfiguration, out *config.DeschedulerConfiguration, s conversion.Scope) error { + if err := v1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + if err := v1.Convert_Pointer_string_To_string(&in.HealthzBindAddress, &out.HealthzBindAddress, s); err != nil { + return err + } + if err := v1.Convert_Pointer_string_To_string(&in.MetricsBindAddress, &out.MetricsBindAddress, s); err != nil { + return err + } + out.DeschedulingInterval = in.DeschedulingInterval + out.DryRun = in.DryRun + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]config.DeschedulerProfile, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.NodeSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NodeSelector)) + return nil +} + +func autoConvert_config_DeschedulerConfiguration_To_v1alpha2_DeschedulerConfiguration(in *config.DeschedulerConfiguration, out *DeschedulerConfiguration, s conversion.Scope) error { + if err := v1alpha1.Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + if err := v1.Convert_string_To_Pointer_string(&in.HealthzBindAddress, &out.HealthzBindAddress, s); err != nil { + return err + } + if err := v1.Convert_string_To_Pointer_string(&in.MetricsBindAddress, &out.MetricsBindAddress, s); err != nil { + return err + } + out.DeschedulingInterval = in.DeschedulingInterval + out.DryRun = in.DryRun + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]DeschedulerProfile, len(*in)) + for i := range *in { + if err := Convert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.NodeSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NodeSelector)) + return nil +} + +func autoConvert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile(in *DeschedulerProfile, out *config.DeschedulerProfile, s conversion.Scope) error { + out.Name = in.Name + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]config.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_PluginConfig_To_config_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + out.Plugins = (*config.Plugins)(unsafe.Pointer(in.Plugins)) + return nil +} + +// Convert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile is an autogenerated conversion function. +func Convert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile(in *DeschedulerProfile, out *config.DeschedulerProfile, s conversion.Scope) error { + return autoConvert_v1alpha2_DeschedulerProfile_To_config_DeschedulerProfile(in, out, s) +} + +func autoConvert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile(in *config.DeschedulerProfile, out *DeschedulerProfile, s conversion.Scope) error { + out.Name = in.Name + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + if err := Convert_config_PluginConfig_To_v1alpha2_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + out.Plugins = (*Plugins)(unsafe.Pointer(in.Plugins)) + return nil +} + +// Convert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile is an autogenerated conversion function. +func Convert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile(in *config.DeschedulerProfile, out *DeschedulerProfile, s conversion.Scope) error { + return autoConvert_config_DeschedulerProfile_To_v1alpha2_DeschedulerProfile(in, out, s) +} + +func autoConvert_v1alpha2_Namespaces_To_config_Namespaces(in *Namespaces, out *config.Namespaces, s conversion.Scope) error { + out.Include = *(*[]string)(unsafe.Pointer(&in.Include)) + out.Exclude = *(*[]string)(unsafe.Pointer(&in.Exclude)) + return nil +} + +// Convert_v1alpha2_Namespaces_To_config_Namespaces is an autogenerated conversion function. +func Convert_v1alpha2_Namespaces_To_config_Namespaces(in *Namespaces, out *config.Namespaces, s conversion.Scope) error { + return autoConvert_v1alpha2_Namespaces_To_config_Namespaces(in, out, s) +} + +func autoConvert_config_Namespaces_To_v1alpha2_Namespaces(in *config.Namespaces, out *Namespaces, s conversion.Scope) error { + out.Include = *(*[]string)(unsafe.Pointer(&in.Include)) + out.Exclude = *(*[]string)(unsafe.Pointer(&in.Exclude)) + return nil +} + +// Convert_config_Namespaces_To_v1alpha2_Namespaces is an autogenerated conversion function. +func Convert_config_Namespaces_To_v1alpha2_Namespaces(in *config.Namespaces, out *Namespaces, s conversion.Scope) error { + return autoConvert_config_Namespaces_To_v1alpha2_Namespaces(in, out, s) +} + +func autoConvert_v1alpha2_Plugin_To_config_Plugin(in *Plugin, out *config.Plugin, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_v1alpha2_Plugin_To_config_Plugin is an autogenerated conversion function. +func Convert_v1alpha2_Plugin_To_config_Plugin(in *Plugin, out *config.Plugin, s conversion.Scope) error { + return autoConvert_v1alpha2_Plugin_To_config_Plugin(in, out, s) +} + +func autoConvert_config_Plugin_To_v1alpha2_Plugin(in *config.Plugin, out *Plugin, s conversion.Scope) error { + out.Name = in.Name + return nil +} + +// Convert_config_Plugin_To_v1alpha2_Plugin is an autogenerated conversion function. +func Convert_config_Plugin_To_v1alpha2_Plugin(in *config.Plugin, out *Plugin, s conversion.Scope) error { + return autoConvert_config_Plugin_To_v1alpha2_Plugin(in, out, s) +} + +func autoConvert_v1alpha2_PluginConfig_To_config_PluginConfig(in *PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha2_PluginConfig_To_config_PluginConfig is an autogenerated conversion function. +func Convert_v1alpha2_PluginConfig_To_config_PluginConfig(in *PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + return autoConvert_v1alpha2_PluginConfig_To_config_PluginConfig(in, out, s) +} + +func autoConvert_config_PluginConfig_To_v1alpha2_PluginConfig(in *config.PluginConfig, out *PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_config_PluginConfig_To_v1alpha2_PluginConfig is an autogenerated conversion function. +func Convert_config_PluginConfig_To_v1alpha2_PluginConfig(in *config.PluginConfig, out *PluginConfig, s conversion.Scope) error { + return autoConvert_config_PluginConfig_To_v1alpha2_PluginConfig(in, out, s) +} + +func autoConvert_v1alpha2_PluginSet_To_config_PluginSet(in *PluginSet, out *config.PluginSet, s conversion.Scope) error { + out.Enabled = *(*[]config.Plugin)(unsafe.Pointer(&in.Enabled)) + out.Disabled = *(*[]config.Plugin)(unsafe.Pointer(&in.Disabled)) + return nil +} + +// Convert_v1alpha2_PluginSet_To_config_PluginSet is an autogenerated conversion function. +func Convert_v1alpha2_PluginSet_To_config_PluginSet(in *PluginSet, out *config.PluginSet, s conversion.Scope) error { + return autoConvert_v1alpha2_PluginSet_To_config_PluginSet(in, out, s) +} + +func autoConvert_config_PluginSet_To_v1alpha2_PluginSet(in *config.PluginSet, out *PluginSet, s conversion.Scope) error { + out.Enabled = *(*[]Plugin)(unsafe.Pointer(&in.Enabled)) + out.Disabled = *(*[]Plugin)(unsafe.Pointer(&in.Disabled)) + return nil +} + +// Convert_config_PluginSet_To_v1alpha2_PluginSet is an autogenerated conversion function. +func Convert_config_PluginSet_To_v1alpha2_PluginSet(in *config.PluginSet, out *PluginSet, s conversion.Scope) error { + return autoConvert_config_PluginSet_To_v1alpha2_PluginSet(in, out, s) +} + +func autoConvert_v1alpha2_Plugins_To_config_Plugins(in *Plugins, out *config.Plugins, s conversion.Scope) error { + if err := Convert_v1alpha2_PluginSet_To_config_PluginSet(&in.Deschedule, &out.Deschedule, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_config_PluginSet(&in.Balance, &out.Balance, s); err != nil { + return err + } + if err := Convert_v1alpha2_PluginSet_To_config_PluginSet(&in.Evictor, &out.Evictor, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha2_Plugins_To_config_Plugins is an autogenerated conversion function. +func Convert_v1alpha2_Plugins_To_config_Plugins(in *Plugins, out *config.Plugins, s conversion.Scope) error { + return autoConvert_v1alpha2_Plugins_To_config_Plugins(in, out, s) +} + +func autoConvert_config_Plugins_To_v1alpha2_Plugins(in *config.Plugins, out *Plugins, s conversion.Scope) error { + if err := Convert_config_PluginSet_To_v1alpha2_PluginSet(&in.Deschedule, &out.Deschedule, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1alpha2_PluginSet(&in.Balance, &out.Balance, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1alpha2_PluginSet(&in.Evictor, &out.Evictor, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugins_To_v1alpha2_Plugins is an autogenerated conversion function. +func Convert_config_Plugins_To_v1alpha2_Plugins(in *config.Plugins, out *Plugins, s conversion.Scope) error { + return autoConvert_config_Plugins_To_v1alpha2_Plugins(in, out, s) +} + +func autoConvert_v1alpha2_PriorityThreshold_To_config_PriorityThreshold(in *PriorityThreshold, out *config.PriorityThreshold, s conversion.Scope) error { + out.Value = (*int32)(unsafe.Pointer(in.Value)) + out.Name = in.Name + return nil +} + +// Convert_v1alpha2_PriorityThreshold_To_config_PriorityThreshold is an autogenerated conversion function. +func Convert_v1alpha2_PriorityThreshold_To_config_PriorityThreshold(in *PriorityThreshold, out *config.PriorityThreshold, s conversion.Scope) error { + return autoConvert_v1alpha2_PriorityThreshold_To_config_PriorityThreshold(in, out, s) +} + +func autoConvert_config_PriorityThreshold_To_v1alpha2_PriorityThreshold(in *config.PriorityThreshold, out *PriorityThreshold, s conversion.Scope) error { + out.Value = (*int32)(unsafe.Pointer(in.Value)) + out.Name = in.Name + return nil +} + +// Convert_config_PriorityThreshold_To_v1alpha2_PriorityThreshold is an autogenerated conversion function. +func Convert_config_PriorityThreshold_To_v1alpha2_PriorityThreshold(in *config.PriorityThreshold, out *PriorityThreshold, s conversion.Scope) error { + return autoConvert_config_PriorityThreshold_To_v1alpha2_PriorityThreshold(in, out, s) +} + +func autoConvert_v1alpha2_RemovePodsViolatingNodeAffinityArgs_To_config_RemovePodsViolatingNodeAffinityArgs(in *RemovePodsViolatingNodeAffinityArgs, out *config.RemovePodsViolatingNodeAffinityArgs, s conversion.Scope) error { + out.Namespaces = (*config.Namespaces)(unsafe.Pointer(in.Namespaces)) + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.NodeAffinityType = *(*[]string)(unsafe.Pointer(&in.NodeAffinityType)) + return nil +} + +// Convert_v1alpha2_RemovePodsViolatingNodeAffinityArgs_To_config_RemovePodsViolatingNodeAffinityArgs is an autogenerated conversion function. +func Convert_v1alpha2_RemovePodsViolatingNodeAffinityArgs_To_config_RemovePodsViolatingNodeAffinityArgs(in *RemovePodsViolatingNodeAffinityArgs, out *config.RemovePodsViolatingNodeAffinityArgs, s conversion.Scope) error { + return autoConvert_v1alpha2_RemovePodsViolatingNodeAffinityArgs_To_config_RemovePodsViolatingNodeAffinityArgs(in, out, s) +} + +func autoConvert_config_RemovePodsViolatingNodeAffinityArgs_To_v1alpha2_RemovePodsViolatingNodeAffinityArgs(in *config.RemovePodsViolatingNodeAffinityArgs, out *RemovePodsViolatingNodeAffinityArgs, s conversion.Scope) error { + out.Namespaces = (*Namespaces)(unsafe.Pointer(in.Namespaces)) + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.NodeAffinityType = *(*[]string)(unsafe.Pointer(&in.NodeAffinityType)) + return nil +} + +// Convert_config_RemovePodsViolatingNodeAffinityArgs_To_v1alpha2_RemovePodsViolatingNodeAffinityArgs is an autogenerated conversion function. +func Convert_config_RemovePodsViolatingNodeAffinityArgs_To_v1alpha2_RemovePodsViolatingNodeAffinityArgs(in *config.RemovePodsViolatingNodeAffinityArgs, out *RemovePodsViolatingNodeAffinityArgs, s conversion.Scope) error { + return autoConvert_config_RemovePodsViolatingNodeAffinityArgs_To_v1alpha2_RemovePodsViolatingNodeAffinityArgs(in, out, s) +} diff --git a/pkg/descheduler/apis/config/v1alpha2/zz_generated.deepcopy.go b/pkg/descheduler/apis/config/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 000000000..3f12d171d --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,321 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultEvictorArgs) DeepCopyInto(out *DefaultEvictorArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DryRun != nil { + in, out := &in.DryRun, &out.DryRun + *out = new(bool) + **out = **in + } + if in.MaxNoOfPodsToEvictPerNode != nil { + in, out := &in.MaxNoOfPodsToEvictPerNode, &out.MaxNoOfPodsToEvictPerNode + *out = new(int) + **out = **in + } + if in.MaxNoOfPodsToEvictPerNamespace != nil { + in, out := &in.MaxNoOfPodsToEvictPerNamespace, &out.MaxNoOfPodsToEvictPerNamespace + *out = new(int) + **out = **in + } + if in.PriorityThreshold != nil { + in, out := &in.PriorityThreshold, &out.PriorityThreshold + *out = new(PriorityThreshold) + (*in).DeepCopyInto(*out) + } + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultEvictorArgs. +func (in *DefaultEvictorArgs) DeepCopy() *DefaultEvictorArgs { + if in == nil { + return nil + } + out := new(DefaultEvictorArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultEvictorArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeschedulerConfiguration) DeepCopyInto(out *DeschedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + in.LeaderElection.DeepCopyInto(&out.LeaderElection) + out.ClientConnection = in.ClientConnection + in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration) + if in.HealthzBindAddress != nil { + in, out := &in.HealthzBindAddress, &out.HealthzBindAddress + *out = new(string) + **out = **in + } + if in.MetricsBindAddress != nil { + in, out := &in.MetricsBindAddress, &out.MetricsBindAddress + *out = new(string) + **out = **in + } + out.DeschedulingInterval = in.DeschedulingInterval + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]DeschedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerConfiguration. +func (in *DeschedulerConfiguration) DeepCopy() *DeschedulerConfiguration { + if in == nil { + return nil + } + out := new(DeschedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeschedulerProfile) DeepCopyInto(out *DeschedulerProfile) { + *out = *in + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerProfile. +func (in *DeschedulerProfile) DeepCopy() *DeschedulerProfile { + if in == nil { + return nil + } + out := new(DeschedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Namespaces) DeepCopyInto(out *Namespaces) { + *out = *in + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Exclude != nil { + in, out := &in.Exclude, &out.Exclude + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Namespaces. +func (in *Namespaces) DeepCopy() *Namespaces { + if in == nil { + return nil + } + out := new(Namespaces) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.Deschedule.DeepCopyInto(&out.Deschedule) + in.Balance.DeepCopyInto(&out.Balance) + in.Evictor.DeepCopyInto(&out.Evictor) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PriorityThreshold) DeepCopyInto(out *PriorityThreshold) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PriorityThreshold. +func (in *PriorityThreshold) DeepCopy() *PriorityThreshold { + if in == nil { + return nil + } + out := new(PriorityThreshold) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyInto(out *RemovePodsViolatingNodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = new(Namespaces) + (*in).DeepCopyInto(*out) + } + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.NodeAffinityType != nil { + in, out := &in.NodeAffinityType, &out.NodeAffinityType + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemovePodsViolatingNodeAffinityArgs. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopy() *RemovePodsViolatingNodeAffinityArgs { + if in == nil { + return nil + } + out := new(RemovePodsViolatingNodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/descheduler/apis/config/v1alpha2/zz_generated.defaults.go b/pkg/descheduler/apis/config/v1alpha2/zz_generated.defaults.go new file mode 100644 index 000000000..200ffc96a --- /dev/null +++ b/pkg/descheduler/apis/config/v1alpha2/zz_generated.defaults.go @@ -0,0 +1,50 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&DefaultEvictorArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultEvictorArgs(obj.(*DefaultEvictorArgs)) }) + scheme.AddTypeDefaultingFunc(&DeschedulerConfiguration{}, func(obj interface{}) { SetObjectDefaults_DeschedulerConfiguration(obj.(*DeschedulerConfiguration)) }) + scheme.AddTypeDefaultingFunc(&RemovePodsViolatingNodeAffinityArgs{}, func(obj interface{}) { + SetObjectDefaults_RemovePodsViolatingNodeAffinityArgs(obj.(*RemovePodsViolatingNodeAffinityArgs)) + }) + return nil +} + +func SetObjectDefaults_DefaultEvictorArgs(in *DefaultEvictorArgs) { + SetDefaults_DefaultEvictorArgs(in) +} + +func SetObjectDefaults_DeschedulerConfiguration(in *DeschedulerConfiguration) { + SetDefaults_DeschedulerConfiguration(in) +} + +func SetObjectDefaults_RemovePodsViolatingNodeAffinityArgs(in *RemovePodsViolatingNodeAffinityArgs) { + SetDefaults_RemovePodsViolatingNodeAffinityArgs(in) +} diff --git a/pkg/descheduler/apis/config/validation/validation.go b/pkg/descheduler/apis/config/validation/validation.go new file mode 100644 index 000000000..381dc5b33 --- /dev/null +++ b/pkg/descheduler/apis/config/validation/validation.go @@ -0,0 +1,107 @@ +/* +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 validation + +import ( + "reflect" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + componentbasevalidation "k8s.io/component-base/config/validation" + + "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" +) + +func ValidateDeschedulerConfiguration(cc *config.DeschedulerConfiguration) utilerrors.Aggregate { + var errs []error + errs = append(errs, componentbasevalidation.ValidateClientConnectionConfiguration(&cc.ClientConnection, field.NewPath("clientConnection")).ToAggregate()) + errs = append(errs, componentbasevalidation.ValidateLeaderElectionConfiguration(&cc.LeaderElection, field.NewPath("leaderElection")).ToAggregate()) + profilesPath := field.NewPath("profiles") + if len(cc.Profiles) == 0 { + errs = append(errs, field.Required(profilesPath, "")) + } else { + existingProfiles := make(map[string]int, len(cc.Profiles)) + for i := range cc.Profiles { + profile := &cc.Profiles[i] + path := profilesPath.Index(i) + errs = append(errs, validateDeschedulerProfile(path, profile)...) + if idx, ok := existingProfiles[profile.Name]; ok { + errs = append(errs, field.Duplicate(path.Child("name"), profilesPath.Index(idx).Child("name"))) + } + existingProfiles[profile.Name] = i + } + } + for _, msg := range validation.IsValidSocketAddr(cc.HealthzBindAddress) { + errs = append(errs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, msg)) + } + for _, msg := range validation.IsValidSocketAddr(cc.MetricsBindAddress) { + errs = append(errs, field.Invalid(field.NewPath("metricsBindAddress"), cc.MetricsBindAddress, msg)) + } + + if cc.NodeSelector != nil { + _, err := metav1.LabelSelectorAsSelector(cc.NodeSelector) + if err != nil { + errs = append(errs, err) + } + } + + return utilerrors.Flatten(utilerrors.NewAggregate(errs)) +} + +func validateDeschedulerProfile(path *field.Path, profile *config.DeschedulerProfile) []error { + var errs []error + if len(profile.Name) == 0 { + errs = append(errs, field.Required(path.Child("name"), "")) + } + errs = append(errs, validatePluginConfig(path, profile)...) + return errs +} + +func validatePluginConfig(path *field.Path, profile *config.DeschedulerProfile) []error { + var errs []error + m := map[string]interface{}{} + + seenPluginConfig := make(sets.String) + + for i := range profile.PluginConfig { + pluginConfigPath := path.Child("pluginConfig").Index(i) + name := profile.PluginConfig[i].Name + args := profile.PluginConfig[i].Args + if seenPluginConfig.Has(name) { + errs = append(errs, field.Duplicate(pluginConfigPath, name)) + } else { + seenPluginConfig.Insert(name) + } + if validateFunc, ok := m[name]; ok { + // type mismatch, no need to validate the `args`. + if reflect.TypeOf(args) != reflect.ValueOf(validateFunc).Type().In(1) { + errs = append(errs, field.Invalid(pluginConfigPath.Child("args"), args, "has to match plugin args")) + } else { + in := []reflect.Value{reflect.ValueOf(pluginConfigPath.Child("args")), reflect.ValueOf(args)} + res := reflect.ValueOf(validateFunc).Call(in) + // It's possible that validation function return a Aggregate, just append here and it will be flattened at the end of CC validation. + if res[0].Interface() != nil { + errs = append(errs, res[0].Interface().(error)) + } + } + } + } + return errs +} diff --git a/pkg/descheduler/apis/config/validation/validation_pluginargs.go b/pkg/descheduler/apis/config/validation/validation_pluginargs.go new file mode 100644 index 000000000..1a767326b --- /dev/null +++ b/pkg/descheduler/apis/config/validation/validation_pluginargs.go @@ -0,0 +1,35 @@ +/* +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 validation + +import ( + "fmt" + + deschedulerconfig "github.com/koordinator-sh/koordinator/pkg/descheduler/apis/config" +) + +func ValidateRemovePodsViolatingNodeAffinityArgs(params *deschedulerconfig.RemovePodsViolatingNodeAffinityArgs) error { + if params == nil || len(params.NodeAffinityType) == 0 { + return fmt.Errorf("NodeAffinityType is empty") + } + // At most one of include/exclude can be set + if params.Namespaces != nil && len(params.Namespaces.Include) > 0 && len(params.Namespaces.Exclude) > 0 { + return fmt.Errorf("only one of Include/Exclude namespaces can be set") + } + + return nil +} diff --git a/pkg/descheduler/apis/config/zz_generated.deepcopy.go b/pkg/descheduler/apis/config/zz_generated.deepcopy.go new file mode 100644 index 000000000..ea45d14dd --- /dev/null +++ b/pkg/descheduler/apis/config/zz_generated.deepcopy.go @@ -0,0 +1,308 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultEvictorArgs) DeepCopyInto(out *DefaultEvictorArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.MaxNoOfPodsToEvictPerNode != nil { + in, out := &in.MaxNoOfPodsToEvictPerNode, &out.MaxNoOfPodsToEvictPerNode + *out = new(int) + **out = **in + } + if in.MaxNoOfPodsToEvictPerNamespace != nil { + in, out := &in.MaxNoOfPodsToEvictPerNamespace, &out.MaxNoOfPodsToEvictPerNamespace + *out = new(int) + **out = **in + } + if in.PriorityThreshold != nil { + in, out := &in.PriorityThreshold, &out.PriorityThreshold + *out = new(PriorityThreshold) + (*in).DeepCopyInto(*out) + } + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultEvictorArgs. +func (in *DefaultEvictorArgs) DeepCopy() *DefaultEvictorArgs { + if in == nil { + return nil + } + out := new(DefaultEvictorArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultEvictorArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeschedulerConfiguration) DeepCopyInto(out *DeschedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + out.LeaderElection = in.LeaderElection + out.ClientConnection = in.ClientConnection + out.DebuggingConfiguration = in.DebuggingConfiguration + out.DeschedulingInterval = in.DeschedulingInterval + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]DeschedulerProfile, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerConfiguration. +func (in *DeschedulerConfiguration) DeepCopy() *DeschedulerConfiguration { + if in == nil { + return nil + } + out := new(DeschedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DeschedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeschedulerProfile) DeepCopyInto(out *DeschedulerProfile) { + *out = *in + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]PluginConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = new(Plugins) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeschedulerProfile. +func (in *DeschedulerProfile) DeepCopy() *DeschedulerProfile { + if in == nil { + return nil + } + out := new(DeschedulerProfile) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Namespaces) DeepCopyInto(out *Namespaces) { + *out = *in + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Exclude != nil { + in, out := &in.Exclude, &out.Exclude + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Namespaces. +func (in *Namespaces) DeepCopy() *Namespaces { + if in == nil { + return nil + } + out := new(Namespaces) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugin) DeepCopyInto(out *Plugin) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + if in.Args != nil { + out.Args = in.Args.DeepCopyObject() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.Deschedule.DeepCopyInto(&out.Deschedule) + in.Balance.DeepCopyInto(&out.Balance) + in.Evictor.DeepCopyInto(&out.Evictor) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PriorityThreshold) DeepCopyInto(out *PriorityThreshold) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PriorityThreshold. +func (in *PriorityThreshold) DeepCopy() *PriorityThreshold { + if in == nil { + return nil + } + out := new(PriorityThreshold) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyInto(out *RemovePodsViolatingNodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = new(Namespaces) + (*in).DeepCopyInto(*out) + } + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.NodeAffinityType != nil { + in, out := &in.NodeAffinityType, &out.NodeAffinityType + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemovePodsViolatingNodeAffinityArgs. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopy() *RemovePodsViolatingNodeAffinityArgs { + if in == nil { + return nil + } + out := new(RemovePodsViolatingNodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RemovePodsViolatingNodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +}