* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
135 lines
3.9 KiB
Go
135 lines
3.9 KiB
Go
/*
|
|
* Please refer to the LICENSE file in the root directory of the project.
|
|
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
|
|
*/
|
|
|
|
package group
|
|
|
|
import (
|
|
"context"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/util/validation"
|
|
"k8s.io/client-go/tools/record"
|
|
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/builder"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
|
|
|
"kubesphere.io/kubesphere/pkg/controller"
|
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
|
)
|
|
|
|
const (
|
|
controllerName = "group"
|
|
finalizer = "finalizers.kubesphere.io/groups"
|
|
)
|
|
|
|
type Reconciler struct {
|
|
client.Client
|
|
|
|
recorder record.EventRecorder
|
|
}
|
|
|
|
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
r.recorder = mgr.GetEventRecorderFor(controllerName)
|
|
r.Client = mgr.GetClient()
|
|
return builder.
|
|
ControllerManagedBy(mgr).
|
|
For(
|
|
&iamv1beta1.Group{},
|
|
builder.WithPredicates(
|
|
predicate.ResourceVersionChangedPredicate{},
|
|
),
|
|
).
|
|
Named(controllerName).
|
|
Complete(r)
|
|
}
|
|
|
|
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
group := &iamv1beta1.Group{}
|
|
if err := r.Get(ctx, req.NamespacedName, group); err != nil {
|
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
|
}
|
|
|
|
if group.ObjectMeta.DeletionTimestamp.IsZero() {
|
|
var g *iamv1beta1.Group
|
|
if !sliceutil.HasString(group.Finalizers, finalizer) {
|
|
g = group.DeepCopy()
|
|
g.ObjectMeta.Finalizers = append(g.ObjectMeta.Finalizers, finalizer)
|
|
}
|
|
|
|
if g != nil {
|
|
return ctrl.Result{}, r.Update(ctx, g)
|
|
}
|
|
} else {
|
|
// The object is being deleted
|
|
if sliceutil.HasString(group.ObjectMeta.Finalizers, finalizer) {
|
|
if err := r.deleteGroupBindings(ctx, group); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
|
|
if err := r.deleteRoleBindings(ctx, group); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
|
|
group.Finalizers = sliceutil.RemoveString(group.ObjectMeta.Finalizers, func(item string) bool {
|
|
return item == finalizer
|
|
})
|
|
|
|
return ctrl.Result{}, r.Update(ctx, group)
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
// TODO: sync logic needs to be updated and no longer relies on KubeFed, it needs to be synchronized manually.
|
|
|
|
r.recorder.Event(group, corev1.EventTypeNormal, controller.Synced, controller.MessageResourceSynced)
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *Reconciler) deleteGroupBindings(ctx context.Context, group *iamv1beta1.Group) error {
|
|
if len(group.Name) > validation.LabelValueMaxLength {
|
|
// ignore invalid label value error
|
|
return nil
|
|
}
|
|
|
|
// Group bindings that created by kubesphere will be deleted directly.
|
|
return r.DeleteAllOf(ctx, &iamv1beta1.GroupBinding{}, client.GracePeriodSeconds(0), client.MatchingLabelsSelector{
|
|
Selector: labels.SelectorFromValidatedSet(labels.Set{iamv1beta1.GroupReferenceLabel: group.Name}),
|
|
})
|
|
}
|
|
|
|
// remove all RoleBindings.
|
|
func (r *Reconciler) deleteRoleBindings(ctx context.Context, group *iamv1beta1.Group) error {
|
|
if len(group.Name) > validation.LabelValueMaxLength {
|
|
// ignore invalid label value error
|
|
return nil
|
|
}
|
|
|
|
selector := labels.SelectorFromValidatedSet(labels.Set{iamv1beta1.GroupReferenceLabel: group.Name})
|
|
deleteOption := client.GracePeriodSeconds(0)
|
|
|
|
if err := r.DeleteAllOf(ctx, &iamv1beta1.WorkspaceRoleBinding{}, deleteOption, client.MatchingLabelsSelector{Selector: selector}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := r.DeleteAllOf(ctx, &rbacv1.ClusterRoleBinding{}, deleteOption, client.MatchingLabelsSelector{Selector: selector}); err != nil {
|
|
return err
|
|
}
|
|
|
|
namespaces := &corev1.NamespaceList{}
|
|
if err := r.List(ctx, namespaces); err != nil {
|
|
return err
|
|
}
|
|
for _, namespace := range namespaces.Items {
|
|
if err := r.DeleteAllOf(ctx, &rbacv1.RoleBinding{}, deleteOption, client.MatchingLabelsSelector{Selector: selector}, client.InNamespace(namespace.Name)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|