-
Notifications
You must be signed in to change notification settings - Fork 901
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4078 from chaosi-zju/retain-2
retain for hpa controlled Deployment resource (labels method)
- Loading branch information
Showing
9 changed files
with
370 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
pkg/controllers/hpareplicassyncer/hpa_replicas_syncer_predicate.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package hpareplicassyncer | ||
|
||
import ( | ||
autoscalingv2 "k8s.io/api/autoscaling/v2" | ||
"k8s.io/klog/v2" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
|
||
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" | ||
) | ||
|
||
var _ predicate.Predicate = &HPAReplicasSyncer{} | ||
|
||
func (r *HPAReplicasSyncer) Create(e event.CreateEvent) bool { | ||
hpa, ok := e.Object.(*autoscalingv2.HorizontalPodAutoscaler) | ||
if !ok { | ||
klog.Errorf("create predicates in hpa controller called, but obj is not hpa type") | ||
return false | ||
} | ||
|
||
// if hpa exist and has been propagated, add label to its scale ref resource | ||
if hasBeenPropagated(hpa) { | ||
r.scaleRefWorker.Add(labelEvent{addLabelEvent, hpa}) | ||
} | ||
|
||
return false | ||
} | ||
|
||
func (r *HPAReplicasSyncer) Update(e event.UpdateEvent) bool { | ||
oldHPA, ok := e.ObjectOld.(*autoscalingv2.HorizontalPodAutoscaler) | ||
if !ok { | ||
klog.Errorf("update predicates in hpa controller called, but old obj is not hpa type") | ||
return false | ||
} | ||
|
||
newHPA, ok := e.ObjectNew.(*autoscalingv2.HorizontalPodAutoscaler) | ||
if !ok { | ||
klog.Errorf("update predicates in hpa controller called, but new obj is not hpa type") | ||
return false | ||
} | ||
|
||
// hpa scale ref changed, remove old hpa label and add to new hpa | ||
if oldHPA.Spec.ScaleTargetRef.String() != newHPA.Spec.ScaleTargetRef.String() { | ||
// if scale ref has label, remove label, otherwise skip | ||
r.scaleRefWorker.Add(labelEvent{deleteLabelEvent, oldHPA}) | ||
} | ||
|
||
// if new hpa exist and has been propagated, add label to its scale ref resource | ||
if hasBeenPropagated(newHPA) { | ||
r.scaleRefWorker.Add(labelEvent{addLabelEvent, newHPA}) | ||
} | ||
|
||
return oldHPA.Status.CurrentReplicas != newHPA.Status.CurrentReplicas | ||
} | ||
|
||
func (r *HPAReplicasSyncer) Delete(e event.DeleteEvent) bool { | ||
hpa, ok := e.Object.(*autoscalingv2.HorizontalPodAutoscaler) | ||
if !ok { | ||
klog.Errorf("delete predicates in hpa controller called, but obj is not hpa type") | ||
return false | ||
} | ||
|
||
// if scale ref has label, remove label, otherwise skip | ||
r.scaleRefWorker.Add(labelEvent{deleteLabelEvent, hpa}) | ||
|
||
return false | ||
} | ||
|
||
func (r *HPAReplicasSyncer) Generic(e event.GenericEvent) bool { | ||
return false | ||
} | ||
|
||
func hasBeenPropagated(hpa *autoscalingv2.HorizontalPodAutoscaler) bool { | ||
_, ppExist := hpa.GetLabels()[policyv1alpha1.PropagationPolicyUIDLabel] | ||
_, cppExist := hpa.GetLabels()[policyv1alpha1.ClusterPropagationPolicyUIDLabel] | ||
return ppExist || cppExist | ||
} |
137 changes: 137 additions & 0 deletions
137
pkg/controllers/hpareplicassyncer/hpa_scale_ref_worker.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package hpareplicassyncer | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
autoscalingv2 "k8s.io/api/autoscaling/v2" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/klog/v2" | ||
|
||
"github.com/karmada-io/karmada/pkg/util" | ||
"github.com/karmada-io/karmada/pkg/util/helper" | ||
) | ||
|
||
type labelEventKind int | ||
|
||
const ( | ||
// addLabelEvent refer to addding util.RetainReplicasLabel to resource scaled by HPA | ||
addLabelEvent labelEventKind = iota | ||
// deleteLabelEvent refer to deleting util.RetainReplicasLabel from resource scaled by HPA | ||
deleteLabelEvent | ||
) | ||
|
||
type labelEvent struct { | ||
kind labelEventKind | ||
hpa *autoscalingv2.HorizontalPodAutoscaler | ||
} | ||
|
||
func (r *HPAReplicasSyncer) reconcileScaleRef(key util.QueueKey) (err error) { | ||
event, ok := key.(labelEvent) | ||
if !ok { | ||
klog.Errorf("Found invalid key when reconciling hpa scale ref: %+v", key) | ||
return nil | ||
} | ||
|
||
switch event.kind { | ||
case addLabelEvent: | ||
err = r.addHPALabelToScaleRef(context.TODO(), event.hpa) | ||
case deleteLabelEvent: | ||
err = r.deleteHPALabelFromScaleRef(context.TODO(), event.hpa) | ||
default: | ||
klog.Errorf("Found invalid key when reconciling hpa scale ref: %+v", key) | ||
return nil | ||
} | ||
|
||
if err != nil { | ||
klog.Errorf("reconcile scale ref failed: %+v", err) | ||
} | ||
return err | ||
} | ||
|
||
func (r *HPAReplicasSyncer) addHPALabelToScaleRef(ctx context.Context, hpa *autoscalingv2.HorizontalPodAutoscaler) error { | ||
targetGVK := schema.FromAPIVersionAndKind(hpa.Spec.ScaleTargetRef.APIVersion, hpa.Spec.ScaleTargetRef.Kind) | ||
mapping, err := r.RESTMapper.RESTMapping(targetGVK.GroupKind(), targetGVK.Version) | ||
if err != nil { | ||
return fmt.Errorf("unable to recognize scale ref resource, %s/%v, err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
scaleRef, err := r.DynamicClient.Resource(mapping.Resource).Namespace(hpa.Namespace).Get(ctx, hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
klog.Infof("scale ref resource is not found (%s/%v), skip processing", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
return fmt.Errorf("failed to find scale ref resource (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
// use patch is better than update, when modification occur after get, patch can still success while update can not | ||
newScaleRef := scaleRef.DeepCopy() | ||
util.MergeLabel(newScaleRef, util.RetainReplicasLabel, util.RetainReplicasValue) | ||
patchBytes, err := helper.GenMergePatch(scaleRef, newScaleRef) | ||
if err != nil { | ||
return fmt.Errorf("failed to gen merge patch (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
if len(patchBytes) == 0 { | ||
klog.Infof("hpa labels already exist, skip adding (%s/%v)", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
|
||
_, err = r.DynamicClient.Resource(mapping.Resource).Namespace(newScaleRef.GetNamespace()). | ||
Patch(ctx, newScaleRef.GetName(), types.MergePatchType, patchBytes, metav1.PatchOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
klog.Infof("scale ref resource is not found (%s/%v), skip processing", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
return fmt.Errorf("failed to patch scale ref resource (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
klog.Infof("add hpa labels to %s/%v success", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
|
||
func (r *HPAReplicasSyncer) deleteHPALabelFromScaleRef(ctx context.Context, hpa *autoscalingv2.HorizontalPodAutoscaler) error { | ||
targetGVK := schema.FromAPIVersionAndKind(hpa.Spec.ScaleTargetRef.APIVersion, hpa.Spec.ScaleTargetRef.Kind) | ||
mapping, err := r.RESTMapper.RESTMapping(targetGVK.GroupKind(), targetGVK.Version) | ||
if err != nil { | ||
return fmt.Errorf("unable to recognize scale ref resource, %s/%v, err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
scaleRef, err := r.DynamicClient.Resource(mapping.Resource).Namespace(hpa.Namespace).Get(ctx, hpa.Spec.ScaleTargetRef.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
klog.Infof("scale ref resource is not found (%s/%v), skip processing", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
return fmt.Errorf("failed to find scale ref resource (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
// use patch is better than update, when modification occur after get, patch can still success while update can not | ||
newScaleRef := scaleRef.DeepCopy() | ||
util.RemoveLabels(newScaleRef, util.RetainReplicasLabel) | ||
patchBytes, err := helper.GenMergePatch(scaleRef, newScaleRef) | ||
if err != nil { | ||
return fmt.Errorf("failed to gen merge patch (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
if len(patchBytes) == 0 { | ||
klog.Infof("hpa labels not exist, skip deleting (%s/%v)", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
|
||
_, err = r.DynamicClient.Resource(mapping.Resource).Namespace(newScaleRef.GetNamespace()). | ||
Patch(ctx, newScaleRef.GetName(), types.MergePatchType, patchBytes, metav1.PatchOptions{}) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
klog.Infof("scale ref resource is not found (%s/%v), skip processing", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} | ||
return fmt.Errorf("failed to patch scale ref resource (%s/%v), err: %+v", hpa.Namespace, hpa.Spec.ScaleTargetRef, err) | ||
} | ||
|
||
klog.Infof("delete hpa labels from %s/%+v success", hpa.Namespace, hpa.Spec.ScaleTargetRef) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.