mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-02-14 10:00:11 +00:00
130 lines
4.1 KiB
Go
130 lines
4.1 KiB
Go
package v1
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
|
|
|
clusterv1 "open-cluster-management.io/api/cluster/v1"
|
|
clusterv1beta2 "open-cluster-management.io/api/cluster/v1beta2"
|
|
ocmfeature "open-cluster-management.io/api/feature"
|
|
|
|
"open-cluster-management.io/ocm/pkg/features"
|
|
"open-cluster-management.io/ocm/pkg/registration/helpers"
|
|
)
|
|
|
|
var (
|
|
nowFunc = time.Now
|
|
defaultClusterSetName = "default"
|
|
_ webhook.CustomDefaulter = &ManagedClusterWebhook{}
|
|
)
|
|
|
|
func (r *ManagedClusterWebhook) Default(ctx context.Context, obj runtime.Object) error {
|
|
req, err := admission.RequestFromContext(ctx)
|
|
if err != nil {
|
|
return apierrors.NewBadRequest(err.Error())
|
|
}
|
|
|
|
var oldManagedCluster *clusterv1.ManagedCluster
|
|
if len(req.OldObject.Raw) > 0 {
|
|
cluster := &clusterv1.ManagedCluster{}
|
|
if err := json.Unmarshal(req.OldObject.Raw, cluster); err != nil {
|
|
return apierrors.NewBadRequest(err.Error())
|
|
}
|
|
oldManagedCluster = cluster
|
|
}
|
|
|
|
managedCluster, ok := obj.(*clusterv1.ManagedCluster)
|
|
if !ok {
|
|
return apierrors.NewBadRequest("Request cluster obj format is not right")
|
|
}
|
|
|
|
// Generate taints
|
|
err = r.processTaints(managedCluster, oldManagedCluster)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set default clusterset label
|
|
if features.HubMutableFeatureGate.Enabled(ocmfeature.DefaultClusterSet) {
|
|
r.addDefaultClusterSetLabel(managedCluster)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// processTaints set cluster taints
|
|
func (r *ManagedClusterWebhook) processTaints(managedCluster, oldManagedCluster *clusterv1.ManagedCluster) error {
|
|
if len(managedCluster.Spec.Taints) == 0 {
|
|
return nil
|
|
}
|
|
now := metav1.NewTime(nowFunc())
|
|
var invalidTaints []string
|
|
for index, taint := range managedCluster.Spec.Taints {
|
|
originalTaint := helpers.FindTaintByKey(oldManagedCluster, taint.Key)
|
|
switch {
|
|
case oldManagedCluster == nil:
|
|
// handle CREATE operation.
|
|
// The request will not be denied if it has taints with timeAdded specified,
|
|
// while the specified values will be ignored.
|
|
managedCluster.Spec.Taints[index].TimeAdded = now
|
|
case originalTaint == nil:
|
|
// handle UPDATE operation.
|
|
// new taint
|
|
// The request will be denied if it has any taint with timeAdded specified.
|
|
if !taint.TimeAdded.IsZero() {
|
|
invalidTaints = append(invalidTaints, taint.Key)
|
|
continue
|
|
}
|
|
managedCluster.Spec.Taints[index].TimeAdded = now
|
|
case originalTaint.Value == taint.Value && originalTaint.Effect == taint.Effect:
|
|
// handle UPDATE operation.
|
|
// no change
|
|
// The request will be denied if it has any taint with different timeAdded specified.
|
|
timeAdded := taint.TimeAdded
|
|
if !originalTaint.TimeAdded.Equal(&timeAdded) {
|
|
invalidTaints = append(invalidTaints, taint.Key)
|
|
}
|
|
default:
|
|
// handle UPDATE operation.
|
|
// taint's value/effect has changed
|
|
// The request will be denied if it has any taint with timeAdded specified.
|
|
if !taint.TimeAdded.IsZero() {
|
|
invalidTaints = append(invalidTaints, taint.Key)
|
|
continue
|
|
}
|
|
managedCluster.Spec.Taints[index].TimeAdded = now
|
|
}
|
|
}
|
|
|
|
if len(invalidTaints) == 0 {
|
|
return nil
|
|
}
|
|
return apierrors.NewBadRequest(fmt.Sprintf("It is not allowed to set TimeAdded of Taint %q.", strings.Join(invalidTaints, ",")))
|
|
}
|
|
|
|
// addDefaultClusterSetLabel add label "cluster.open-cluster-management.io/clusterset:default" for
|
|
// ManagedCluster if the managedCluster has no ManagedClusterSet label
|
|
func (a *ManagedClusterWebhook) addDefaultClusterSetLabel(managedCluster *clusterv1.ManagedCluster) {
|
|
if len(managedCluster.Labels) == 0 {
|
|
managedCluster.Labels = map[string]string{
|
|
clusterv1beta2.ClusterSetLabel: defaultClusterSetName,
|
|
}
|
|
return
|
|
}
|
|
|
|
clusterSetName, ok := managedCluster.Labels[clusterv1beta2.ClusterSetLabel]
|
|
// Clusterset label do not exist or "", set default clusterset label
|
|
if !ok || len(clusterSetName) == 0 {
|
|
managedCluster.Labels[clusterv1beta2.ClusterSetLabel] = defaultClusterSetName
|
|
}
|
|
}
|