From 55d4ed479c6b8590149c1eb8fe77e47b88750263 Mon Sep 17 00:00:00 2001 From: Amir Alavi Date: Fri, 5 Aug 2022 10:46:04 -0400 Subject: [PATCH] separate args validation for better reuse --- .../validation/validation_pluginargs.go | 23 ++++- .../validation/validation_pluginargs_test.go | 85 +++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 pkg/apis/componentconfig/validation/validation_pluginargs_test.go diff --git a/pkg/apis/componentconfig/validation/validation_pluginargs.go b/pkg/apis/componentconfig/validation/validation_pluginargs.go index fcf94ce428..0c3f9bb400 100644 --- a/pkg/apis/componentconfig/validation/validation_pluginargs.go +++ b/pkg/apis/componentconfig/validation/validation_pluginargs.go @@ -18,6 +18,7 @@ package validation import ( "fmt" + utilerrors "k8s.io/apimachinery/pkg/util/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/descheduler/pkg/api" @@ -26,20 +27,36 @@ import ( // ValidateRemovePodsViolatingNodeTaintsArgs validates RemovePodsViolatingNodeTaints arguments func ValidateRemovePodsViolatingNodeTaintsArgs(args *componentconfig.RemovePodsViolatingNodeTaintsArgs) error { - return validateCommonArgs(args.Namespaces, args.LabelSelector) + return errorsAggregate( + validateNamespaceArgs(args.Namespaces), + validateLabelSelectorArgs(args.LabelSelector), + ) } // ValidateRemoveFailedPodsArgs validates RemoveFailedPods arguments func ValidateRemoveFailedPodsArgs(args *componentconfig.RemoveFailedPodsArgs) error { - return validateCommonArgs(args.Namespaces, args.LabelSelector) + return errorsAggregate( + validateNamespaceArgs(args.Namespaces), + validateLabelSelectorArgs(args.LabelSelector), + ) } -func validateCommonArgs(namespaces *api.Namespaces, labelSelector *metav1.LabelSelector) error { +// errorsAggregate converts all arg validation errors to a single error interface. +// if no errors, it will return nil. +func errorsAggregate(errors ...error) error { + return utilerrors.NewAggregate(errors) +} + +func validateNamespaceArgs(namespaces *api.Namespaces) error { // At most one of include/exclude can be set if namespaces != nil && len(namespaces.Include) > 0 && len(namespaces.Exclude) > 0 { return fmt.Errorf("only one of Include/Exclude namespaces can be set") } + return nil +} + +func validateLabelSelectorArgs(labelSelector *metav1.LabelSelector) error { if labelSelector != nil { if _, err := metav1.LabelSelectorAsSelector(labelSelector); err != nil { return fmt.Errorf("failed to get label selectors from strategy's params: %+v", err) diff --git a/pkg/apis/componentconfig/validation/validation_pluginargs_test.go b/pkg/apis/componentconfig/validation/validation_pluginargs_test.go new file mode 100644 index 0000000000..4e8f2fecc0 --- /dev/null +++ b/pkg/apis/componentconfig/validation/validation_pluginargs_test.go @@ -0,0 +1,85 @@ +/* +Copyright 2022 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 validation + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/descheduler/pkg/api" + "sigs.k8s.io/descheduler/pkg/apis/componentconfig" + "testing" +) + +func TestValidateRemovePodsViolatingNodeTaintsArgs(t *testing.T) { + testCases := []struct { + description string + args *componentconfig.RemovePodsViolatingNodeTaintsArgs + expectError bool + }{ + { + description: "valid namespace args, no errors", + args: &componentconfig.RemovePodsViolatingNodeTaintsArgs{ + Namespaces: &api.Namespaces{ + Include: []string{"default"}, + }, + }, + expectError: false, + }, + { + description: "invalid namespaces args, expects error", + args: &componentconfig.RemovePodsViolatingNodeTaintsArgs{ + Namespaces: &api.Namespaces{ + Include: []string{"default"}, + Exclude: []string{"kube-system"}, + }, + }, + expectError: true, + }, + { + description: "valid label selector args, no errors", + args: &componentconfig.RemovePodsViolatingNodeTaintsArgs{ + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"role.kubernetes.io/node": ""}, + }, + }, + expectError: false, + }, + { + description: "invalid label selector args, expects errors", + args: &componentconfig.RemovePodsViolatingNodeTaintsArgs{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Operator: metav1.LabelSelectorOpIn, + }, + }, + }, + }, + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + err := ValidateRemovePodsViolatingNodeTaintsArgs(tc.args) + + hasError := err != nil + if tc.expectError != hasError { + t.Error("unexpected arg validation behavior") + } + }) + } +}