Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

operationrequest cr change to the user-system #5144

Merged
merged 5 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions controllers/user/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest

## Tool Versions
KUSTOMIZE_VERSION ?= v3.8.7
CONTROLLER_TOOLS_VERSION ?= v0.10.0
KUSTOMIZE_VERSION ?= v5.3.0
CONTROLLER_TOOLS_VERSION ?= v0.14.0

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
Expand Down
1 change: 1 addition & 0 deletions controllers/user/api/v1/deleterequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type DeleteRequestStatus struct {
// +kubebuilder:resource:scope=Cluster
//+kubebuilder:printcolumn:name="User",type="string",JSONPath=".spec.user"
//+kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase"
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"

// DeleteRequest is the Schema for the deleterequests API
type DeleteRequest struct {
Expand Down
6 changes: 5 additions & 1 deletion controllers/user/api/v1/operationrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (

// OperationrequestSpec defines the desired state of Operationrequest
type OperationrequestSpec struct {
User string `json:"user,omitempty"`
// Namespace is the workspace that needs to be operated.
Namespace string `json:"namespace,omitempty"`
User string `json:"user,omitempty"`
// +kubebuilder:validation:Enum=Owner;Manager;Developer
Role RoleType `json:"role,omitempty"`
// +kubebuilder:validation:Enum=Grant;Update;Deprive
Expand Down Expand Up @@ -56,9 +58,11 @@ const (
)

//+kubebuilder:printcolumn:name="Action",type="string",JSONPath=".spec.action"
//+kubebuilder:printcolumn:name="Namespace",type="string",JSONPath=".spec.namespace"
//+kubebuilder:printcolumn:name="User",type="string",JSONPath=".spec.user"
//+kubebuilder:printcolumn:name="Role",type="string",JSONPath=".spec.role"
//+kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase"
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: deleterequests.user.sealos.io
spec:
group: user.sealos.io
Expand All @@ -36,20 +35,28 @@ spec:
- jsonPath: .status.phase
name: Phase
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: DeleteRequest is the Schema for the deleterequests API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: operationrequests.user.sealos.io
spec:
group: user.sealos.io
Expand All @@ -33,6 +32,9 @@ spec:
- jsonPath: .spec.action
name: Action
type: string
- jsonPath: .spec.namespace
name: Namespace
type: string
- jsonPath: .spec.user
name: User
type: string
Expand All @@ -42,20 +44,28 @@ spec:
- jsonPath: .status.phase
name: Phase
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: Operationrequest is the Schema for the operation requests API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand All @@ -68,6 +78,9 @@ spec:
- Update
- Deprive
type: string
namespace:
description: Namespace is the workspace that needs to be operated.
type: string
role:
enum:
- Owner
Expand Down
34 changes: 20 additions & 14 deletions controllers/user/config/crd/bases/user.sealos.io_users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: users.user.sealos.io
spec:
group: user.sealos.io
Expand All @@ -45,14 +44,19 @@ spec:
description: User is the Schema for the users API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
Expand All @@ -61,12 +65,14 @@ spec:
properties:
csrExpirationSeconds:
default: 7200
description: "expirationSeconds is the requested duration of validity
of the issued certificate. The certificate signer may issue a certificate
with a different validity duration so a client must check the delta
between the notBefore and notAfter fields in the issued certificate
to determine the actual duration. \n The minimum valid value for
expirationSeconds is 600, i.e. 10 minutes."
description: |-
expirationSeconds is the requested duration of validity of the issued
certificate. The certificate signer may issue a certificate with a different
validity duration so a client must check the delta between the notBefore and
notAfter fields in the issued certificate to determine the actual duration.


The minimum valid value for expirationSeconds is 600, i.e. 10 minutes.
format: int32
type: integer
type: object
Expand Down
1 change: 0 additions & 1 deletion controllers/user/config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
Expand Down
2 changes: 0 additions & 2 deletions controllers/user/config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
Expand Down Expand Up @@ -63,7 +62,6 @@ webhooks:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
creationTimestamp: null
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
Expand Down
62 changes: 45 additions & 17 deletions controllers/user/controllers/operationrequest_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ package controllers
import (
"context"
"fmt"
"sync"
"time"

"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"

"github.com/go-logr/logr"

util "github.com/labring/operator-sdk/controller"
Expand Down Expand Up @@ -48,6 +53,7 @@ type OperationReqReconciler struct {
Logger logr.Logger
Scheme *runtime.Scheme
Recorder record.EventRecorder
userLock map[string]*sync.Mutex

// expirationTime is the time duration of the request is expired
expirationTime time.Duration
Expand All @@ -68,16 +74,34 @@ func (r *OperationReqReconciler) SetupWithManager(mgr ctrl.Manager, opts util.Ra
r.Scheme = mgr.GetScheme()
r.expirationTime = expTime
r.retentionTime = retTime
r.userLock = make(map[string]*sync.Mutex)
r.Logger.V(1).Info("init reconcile operationrequest controller")
return ctrl.NewControllerManagedBy(mgr).
For(&userv1.Operationrequest{}).
For(&userv1.Operationrequest{}, builder.WithPredicates(namespaceOnlyPredicate(config.GetUserSystemNamespace()))).
WithOptions(controller.Options{
MaxConcurrentReconciles: util.GetConcurrent(opts),
RateLimiter: util.GetRateLimiter(opts),
}).
Complete(r)
}

func namespaceOnlyPredicate(namespace string) predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return e.Object.GetNamespace() == namespace
},
DeleteFunc: func(e event.DeleteEvent) bool {
return e.Object.GetNamespace() == namespace
},
UpdateFunc: func(e event.UpdateEvent) bool {
return e.ObjectNew.GetNamespace() == namespace
},
GenericFunc: func(e event.GenericEvent) bool {
return e.Object.GetNamespace() == namespace
},
}
}

// +kubebuilder:rbac:groups=user.sealos.io,resources=operationrequests,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=user.sealos.io,resources=operationrequests/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=user.sealos.io,resources=operationrequests/finalizers,verbs=update
Expand All @@ -91,6 +115,13 @@ func (r *OperationReqReconciler) Reconcile(ctx context.Context, req ctrl.Request
}

func (r *OperationReqReconciler) reconcile(ctx context.Context, request *userv1.Operationrequest) (ctrl.Result, error) {
userLock, ok := r.userLock[request.Spec.User]
if !ok {
userLock = &sync.Mutex{}
r.userLock[request.Spec.User] = userLock
}
userLock.Lock()
defer userLock.Unlock()
r.Logger.V(1).Info("start reconcile controller operationRequest", getLog(request)...)
// count the time cost of handling the request
startTime := time.Now()
Expand Down Expand Up @@ -136,17 +167,10 @@ func (r *OperationReqReconciler) reconcile(ctx context.Context, request *userv1.
)

user := &userv1.User{}
if err := r.Get(ctx, client.ObjectKey{Name: config.GetUserNameByNamespace(request.Namespace)}, user); err != nil {
if err := r.Get(ctx, client.ObjectKey{Name: config.GetUserNameByNamespace(request.Spec.Namespace)}, user); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to get user", "Failed to get user %s", request.Spec.User)
return ctrl.Result{}, err
}
if request.Spec.Role == userv1.OwnerRoleType {
if user.Name == user.Annotations[userv1.UserAnnotationOwnerKey] {
// 不允许转移个人空间
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to grant role", "Failed to grant role %s to user %s, cannot transfer personal workspace", request.Spec.Role, request.Spec.User)
return ctrl.Result{}, r.updateRequestStatus(ctx, request, userv1.RequestFailed)
}
}
bindUser := &userv1.User{}
if err := r.Get(ctx, client.ObjectKey{Name: request.Spec.User}, bindUser); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to get bind user", "Failed to get bind user %s", request.Spec.User)
Expand Down Expand Up @@ -184,8 +208,12 @@ func (r *OperationReqReconciler) reconcile(ctx context.Context, request *userv1.
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to delete rolebinding", "Failed to delete rolebinding %s/%s", rolebinding.Namespace, rolebinding.Name)
return ctrl.Result{}, err
}
if _, err := ctrl.CreateOrUpdate(ctx, r.Client, rolebinding, setUpOwnerReferenceFc); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to create/update rolebinding", "Failed to create rolebinding %s/%s", rolebinding.Namespace, rolebinding.Name)
if err := r.Create(ctx, rolebinding); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to create rolebinding", "Failed to create rolebinding %s/%s", rolebinding.Namespace, rolebinding.Name)
return ctrl.Result{}, err
}
if err = setUpOwnerReferenceFc(); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to set owner reference", "Failed to set owner reference for rolebinding %s/%s", rolebinding.Namespace, rolebinding.Name)
return ctrl.Result{}, err
}
if request.Spec.Role == userv1.OwnerRoleType {
Expand All @@ -206,7 +234,7 @@ func (r *OperationReqReconciler) reconcile(ctx context.Context, request *userv1.
return ctrl.Result{}, err
}

r.Recorder.Eventf(request, v1.EventTypeNormal, "Completed", "Completed operation request %s/%s", request.Namespace, request.Name)
r.Recorder.Eventf(request, v1.EventTypeNormal, "Completed", "Completed operation request %s/%s", request.Spec.Namespace, request.Name)
return ctrl.Result{RequeueAfter: OperationReqRequeueDuration}, nil
}

Expand Down Expand Up @@ -234,9 +262,9 @@ func (r *OperationReqReconciler) isExpired(request *userv1.Operationrequest) boo
func (r *OperationReqReconciler) deleteRequest(ctx context.Context, request *userv1.Operationrequest) error {
r.Logger.V(1).Info("deleting OperationRequest", "request", request)
if err := r.Delete(ctx, request); client.IgnoreNotFound(err) != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to delete OperationRequest", "Failed to delete OperationRequest %s/%s", request.Namespace, request.Name)
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to delete OperationRequest", "Failed to delete OperationRequest %s/%s", request.Spec.Namespace, request.Name)
r.Logger.Error(err, "Failed to delete OperationRequest", getLog(request)...)
return fmt.Errorf("failed to delete OperationRequest %s/%s: %w", request.Namespace, request.Name, err)
return fmt.Errorf("failed to delete OperationRequest %s/%s: %w", request.Spec.Namespace, request.Name, err)
}
r.Logger.V(1).Info("delete OperationRequest success", getLog(request)...)
return nil
Expand All @@ -245,7 +273,7 @@ func (r *OperationReqReconciler) deleteRequest(ctx context.Context, request *use
func (r *OperationReqReconciler) updateRequestStatus(ctx context.Context, request *userv1.Operationrequest, phase userv1.RequestPhase) error {
request.Status.Phase = phase
if err := r.Status().Update(ctx, request); err != nil {
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to update OperationRequest status", "Failed to update OperationRequest status %s/%s", request.Namespace, request.Name)
r.Recorder.Eventf(request, v1.EventTypeWarning, "Failed to update OperationRequest status", "Failed to update OperationRequest status %s/%s", request.Spec.Namespace, request.Name)
r.Logger.V(1).Info("update OperationRequest status failed", getLog(request)...)
return err
}
Expand All @@ -257,7 +285,7 @@ func conventRequestToRolebinding(request *userv1.Operationrequest) *rbacv1.RoleB
return &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: config.GetGroupRoleBindingName(request.Spec.User),
Namespace: request.Namespace,
Namespace: request.Spec.Namespace,
Annotations: map[string]string{
userAnnotationOwnerKey: request.Spec.User,
},
Expand All @@ -283,7 +311,7 @@ func conventRequestToRolebinding(request *userv1.Operationrequest) *rbacv1.RoleB
func getLog(request *userv1.Operationrequest, kv ...interface{}) []interface{} {
return append([]interface{}{
"request.name", request.Name,
"request.namespace", request.Namespace,
"request.Spec.Namespace", request.Spec.Namespace,
"request.user", request.Spec.User,
"request.role", request.Spec.Role,
"request.action", request.Spec.Action,
Expand Down
Loading
Loading