diff --git a/apis/apps/v1alpha1/sidecarset_types.go b/apis/apps/v1alpha1/sidecarset_types.go index 714d431983..63e5b858e9 100644 --- a/apis/apps/v1alpha1/sidecarset_types.go +++ b/apis/apps/v1alpha1/sidecarset_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + appspub "github.com/openkruise/kruise/apis/apps/pub" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -252,7 +253,9 @@ type SidecarSetUpdateStrategy struct { // This cannot be 0. // Default value is 1. MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` - + // Priorities are the rules for calculating the priority of updating pods. + // Each pod to be updated, will pass through these terms and get a sum of weights. + PriorityStrategy *appspub.UpdatePriorityStrategy `json:"priorityStrategy,omitempty"` // ScatterStrategy defines the scatter rules to make pods been scattered when update. // This will avoid pods with the same key-value to be updated in one batch. // - Note that pods will be scattered after priority sort. So, although priority strategy and scatter strategy can be applied together, we suggest to use either one of them. diff --git a/apis/apps/v1alpha1/zz_generated.deepcopy.go b/apis/apps/v1alpha1/zz_generated.deepcopy.go index c685ae7c5d..2652f045df 100644 --- a/apis/apps/v1alpha1/zz_generated.deepcopy.go +++ b/apis/apps/v1alpha1/zz_generated.deepcopy.go @@ -2950,6 +2950,11 @@ func (in *SidecarSetUpdateStrategy) DeepCopyInto(out *SidecarSetUpdateStrategy) *out = new(intstr.IntOrString) **out = **in } + if in.PriorityStrategy != nil { + in, out := &in.PriorityStrategy, &out.PriorityStrategy + *out = new(pub.UpdatePriorityStrategy) + (*in).DeepCopyInto(*out) + } if in.ScatterStrategy != nil { in, out := &in.ScatterStrategy, &out.ScatterStrategy *out = make(UpdateScatterStrategy, len(*in)) diff --git a/config/crd/bases/apps.kruise.io_sidecarsets.yaml b/config/crd/bases/apps.kruise.io_sidecarsets.yaml index 267b122ff2..071aa9239d 100644 --- a/config/crd/bases/apps.kruise.io_sidecarsets.yaml +++ b/config/crd/bases/apps.kruise.io_sidecarsets.yaml @@ -394,6 +394,96 @@ spec: update the injected pods, but it don't affect the webhook inject sidecar container into the newly created pods. default is false type: boolean + priorityStrategy: + description: Priorities are the rules for calculating the priority + of updating pods. Each pod to be updated, will pass through + these terms and get a sum of weights. + properties: + orderPriority: + description: 'Order priority terms, pods will be sorted by + the value of orderedKey. For example: ``` orderPriority: + - orderedKey: key1 - orderedKey: key2 ``` First, all pods + which have key1 in labels will be sorted by the value of + key1. Then, the left pods which have no key1 but have key2 + in labels will be sorted by the value of key2 and put behind + those pods have key1.' + items: + description: UpdatePriorityOrderTerm defines order priority. + properties: + orderedKey: + description: Calculate priority by value of this key. + Values of this key, will be sorted by GetInt(val). + GetInt method will find the last int in value, such + as getting 5 in value '5', getting 10 in value 'sts-10'. + type: string + required: + - orderedKey + type: object + type: array + weightPriority: + description: Weight priority terms, pods will be sorted by + the sum of all terms weight. + items: + description: UpdatePriorityWeightTerm defines weight priority. + properties: + matchSelector: + description: MatchSelector is used to select by pod's + labels. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + weight: + description: Weight associated with matching the corresponding + matchExpressions, in the range 1-100. + format: int32 + type: integer + required: + - matchSelector + - weight + type: object + type: array + type: object scatterStrategy: description: ScatterStrategy defines the scatter rules to make pods been scattered when update. This will avoid pods with the diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index c6c8eb7dcd..d085403bf6 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -40,14 +40,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index c8ba11f600..fa73f87425 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -40,14 +40,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/pkg/controller/sidecarset/sidecarset_strategy.go b/pkg/controller/sidecarset/sidecarset_strategy.go index edb14d0295..119087232d 100644 --- a/pkg/controller/sidecarset/sidecarset_strategy.go +++ b/pkg/controller/sidecarset/sidecarset_strategy.go @@ -101,6 +101,11 @@ func SortUpdateIndexes(strategy appsv1alpha1.SidecarSetUpdateStrategy, pods []*c // - Empty creation time pods < newer pods < older pods sort.Slice(waitUpdateIndexes, sidecarcontrol.GetPodsSortFunc(pods, waitUpdateIndexes)) + //sort waitUpdateIndexes based on the priority rules + if strategy.PriorityStrategy != nil { + waitUpdateIndexes = updatesort.NewPrioritySorter(strategy.PriorityStrategy).Sort(pods, waitUpdateIndexes) + } + //sort waitUpdateIndexes based on the scatter rules if strategy.ScatterStrategy != nil { // convert regular terms to scatter terms diff --git a/pkg/webhook/sidecarset/validating/sidecarset_create_update_handler.go b/pkg/webhook/sidecarset/validating/sidecarset_create_update_handler.go index bd0e7e28cf..10611abce3 100644 --- a/pkg/webhook/sidecarset/validating/sidecarset_create_update_handler.go +++ b/pkg/webhook/sidecarset/validating/sidecarset_create_update_handler.go @@ -217,6 +217,9 @@ func validateSidecarSetUpdateStrategy(strategy *appsv1alpha1.SidecarSetUpdateStr if strategy.MaxUnavailable != nil { allErrs = append(allErrs, appsvalidation.ValidatePositiveIntOrPercent(*(strategy.MaxUnavailable), fldPath.Child("maxUnavailable"))...) } + if err := strategy.PriorityStrategy.FieldsValidation(); err != nil { + allErrs = append(allErrs, field.Required(fldPath.Child("priorityStrategy"), err.Error())) + } if strategy.ScatterStrategy != nil { if err := strategy.ScatterStrategy.FieldsValidation(); err != nil { allErrs = append(allErrs, field.Required(fldPath.Child("scatterStrategy"), err.Error()))