mirror of
https://github.com/labring/sealos.git
synced 2026-09-01 15:38:06 +08:00
add user-controller webhook (#1766)
* feature(main): delete api logic Signed-off-by: cuisongliu <cuisongliu@qq.com> * feature(main): add user controller webhook Signed-off-by: cuisongliu <cuisongliu@qq.com> Signed-off-by: cuisongliu <cuisongliu@qq.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
|
||||
# Image URL to use all building/pushing image targets
|
||||
IMG ?= ghcr.io/labring/user-controller:dev
|
||||
IMG ?= ghcr.io/labring/user-controller:dev
|
||||
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
|
||||
ENVTEST_K8S_VERSION = 1.24.1
|
||||
|
||||
@@ -99,7 +99,7 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in
|
||||
.PHONY: deploy
|
||||
pre-deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||
$(KUSTOMIZE) build config/default > deploy/manifests/deploy.yaml
|
||||
$(KUSTOMIZE) build -e SERVICE_NAME=webhook-service -e SERVICE_NAMESPACE=system config/default > deploy/manifests/deploy.yaml
|
||||
|
||||
.PHONY: undeploy
|
||||
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||
|
||||
+13
-13
@@ -6,40 +6,40 @@ repo: github.com/labring/sealos/controllers/user
|
||||
resources:
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: sealos.io
|
||||
group: user
|
||||
kind: User
|
||||
path: github.com/labring/sealos/controllers/user/api/v1
|
||||
version: v1
|
||||
webhooks:
|
||||
defaulting: true
|
||||
validation: true
|
||||
webhookVersion: v1
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: sealos.io
|
||||
group: user
|
||||
kind: UserGroupUserBinding
|
||||
kind: UserGroup
|
||||
path: github.com/labring/sealos/controllers/user/api/v1
|
||||
version: v1
|
||||
webhooks:
|
||||
defaulting: true
|
||||
validation: true
|
||||
webhookVersion: v1
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: sealos.io
|
||||
group: user
|
||||
kind: UserGroupNamespaceBinding
|
||||
path: github.com/labring/sealos/controllers/user/api/v1
|
||||
version: v1
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: sealos.io
|
||||
group: user
|
||||
kind: UserGroupBinding
|
||||
path: github.com/labring/sealos/controllers/user/api/v1
|
||||
version: v1
|
||||
webhooks:
|
||||
defaulting: true
|
||||
validation: true
|
||||
webhookVersion: v1
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
|
||||
@@ -212,3 +212,263 @@ subject:
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
userGroupRef: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
```
|
||||
|
||||
|
||||
# add webhook
|
||||
|
||||
```go
|
||||
|
||||
const (
|
||||
UserAnnotationOwnerKey = "user.sealos.io/creator"
|
||||
UserAnnotationDisplayKey = "user.sealos.io/display-name"
|
||||
)
|
||||
|
||||
const (
|
||||
UgNameLabelKey = "user.sealos.io/usergroup.name"
|
||||
UgRoleLabelKey = "user.sealos.io/usergroup.role"
|
||||
UgBindingKindLabelKey = "user.sealos.io/usergroupbinding.kind"
|
||||
UgBindingNameLabelKey = "user.sealos.io/usergroupbinding.name"
|
||||
)
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
items:
|
||||
- apiVersion: user.sealos.io/v1
|
||||
kind: User
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"user.sealos.io/v1","kind":"User","metadata":{"annotations":{},"name":"f8699ded-58d3-432b-a9ff-56568b57a38d"},"spec":{"csrExpirationSeconds":1000000000}}
|
||||
user.sealos.io/display-name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
creationTimestamp: "2022-09-14T14:52:02Z"
|
||||
finalizers:
|
||||
- sealos.io/user.finalizers
|
||||
generation: 1
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
resourceVersion: "416042"
|
||||
uid: 48a7d9e6-5d15-4b26-923c-667d7b8c429f
|
||||
spec:
|
||||
csrExpirationSeconds: 1000000000
|
||||
status:
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: user has been initialized
|
||||
reason: Initialized
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync kube config successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: KubeConfigSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync owner ug successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: OwnerUGSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync owner ug namespace binding successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: OwnerUGNamespaceBindingSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: User is available now
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
kubeConfig: |
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM2VENDQWRHZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQ0FYRFRJeU1Ea3hOREExTlRRMU5Wb1lEekl4TWpJd09ESXhNRFUxTkRVMVdqQVZNUk13RVFZRApWUVFERXdwcmRXSmxjbTVsZEdWek1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCjBMSndEbndvYzV2YittMkpadVplMnB3dkhWZHpyY21SRkdIaUVmQzg4L2hscjVDWllMSkZkNVc5WjRjUFU1VjMKY1NVNG8wL1J1bmNiclNpNmZrdTNFZ0lya1Z0UUkxUm5Ub3ExTUNFeXk1Q3ZvRlpETkMwSW5wRTY2Nng2S0xpagpRZTFyRXYrYmxZc3B4MnE4Tmhtek1zZWR3ZzZod1ErM2RoQ0U5ck9Vb3UwRHZwQ2VKVjAwazkweVRmZGNTN1c0CnJCbFZ1dUhtNVlVU1M3SEZubTBFMUZQd0RONXhNaG9vZmkyVGE3eTZPNzlBZTl5cDZDZlV4cFRra28vOGNwZUIKKzI3NzRNelYyZmJ4Yys0Ri9McWpRTms2VVpIOTlTT3gvTUZJLzFCZWVqeTA1OGdtQ2U3QUlkbEpCdnFQOWRXbwp0cEtlb1ZyN3Fkc0owSEhTeUhmaVNRSURBUUFCbzBJd1FEQU9CZ05WSFE4QkFmOEVCQU1DQXFRd0R3WURWUjBUCkFRSC9CQVV3QXdFQi96QWRCZ05WSFE0RUZnUVVlOW9SQmQ2UVBjNk1VNjcyQjAwOU9nR2VtVjB3RFFZSktvWkkKaHZjTkFRRUxCUUFEZ2dFQkFEYkVDMk9oWkpiUzZldUZmTFNEdG11VlNoc3dFbDRlMFBsWWhnYTBKRHlQSDBUZQpCNmdPWVhZSndrZWxhTWxTUTFFY3ZVa3FHWlhqVUw4Qnl4YzJ0K0pxUDYzQ3ZtZHVzY0NHcWQzTDZTY21UQmZvCjhhbmpENmtoSDZBaHNPVnVsODFYcU9iV2Zxd0diTytGZFgvQi81TDB4bUQ0WUtnNE9iMzdlMWxXb2xJbEJZWmYKMEhqZGNMNjFyYytyWEloeGFPMmlzWHJiSmxzQ0hwTERoVkVKM2o0cjJWdkJFbjRMYWxlZmlYdVdrU3M4RmF0Nwo3N1hwSmhIblA5SHlma0Z1UERsRmpyN1FpcE9wRnJKUXBaeHhmSmREVEhFWUpRV3V0ZytqZjhVZzQweGg5ZS9GCnBNdDlNcTVKSGt3YWVPOEhpSmhaN2dxNjJBQTdseVp4TzBDbnhUYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://192.168.64.29:6443
|
||||
name: sealos
|
||||
contexts:
|
||||
- context:
|
||||
cluster: sealos
|
||||
user: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d@sealos
|
||||
current-context: f8699ded-58d3-432b-a9ff-56568b57a38d@sealos
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lSQU9SY1E5Nnc5UHh6MjBTQXNOKzVoa1V3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWdGdzB5TWpBNU1UUXhORFEzTURKYUdBOHlNRFUwTURVeQpNekUyTXpNME1sb3dMekV0TUNzR0ExVUVBeE1rWmpnMk9UbGtaV1F0TlRoa015MDBNekppTFdFNVptWXROVFkxCk5qaGlOVGRoTXpoa01JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMnB4VHVwNHUKR0xzeVQ1a1RBeldrZGlTSUtnY09OTTkxU3FLV25CM2t1ektaKzUvWkdiT1MrWElGV3IrbEdtbkZnMUY0Sng5Ywpvb3I0K09KTnBSWHdpNElkejgvRVllbGU0cmU1bjE3enlvUHFLWFBGemdjM1pOc2d0Ni9WQm5ENVBYaUlvc3pECnI0dC9RQWh3SFA0VjVyTkIrTUJHbjdtMzJaY1UxNTlFak5sOVJjQWhNZHJWKzAvRVZNN1ZGVThVVnhzZWV1c1QKQlBvTDJOanZwek1NY0VTeFpsY3lVS1lpNG5TamtXR3ZOSnZja1BDaTFHaUhUc1lZZE1qKzRFQTZmZnRKRC9IYwprMkVCWVVVQmlWeXRtVUNRSEZIWm5rU0Eva1FwUFpHVll0Y1VTaDB1bmY4cWwyM2k1RUVsL3M1eTRjSmI0SVdmCmY3anpaWk9uTmpBVlVRSURBUUFCbzFZd1ZEQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0V3WURWUjBsQkF3d0NnWUkKS3dZQkJRVUhBd0l3REFZRFZSMFRBUUgvQkFJd0FEQWZCZ05WSFNNRUdEQVdnQlI3MmhFRjNwQTl6b3hUcnZZSApUVDA2QVo2WlhUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFGdHNUOFlaS1dNelEydUIzZVZqeVVaRXM5dEY4Cms3MXk4YVZIV2owcEVFSTgzUlpSUjNMbzg5V3l4a3p6c0N2NjZYSkdKVHRzWFlYdTVjL1FpZ3NHemhGRTB0WlAKeGRIc3Y4SzRVelZablhSc2Y5U3BWcmNTQnR6WHEveEw5bXJ4VCtLcklBTEEzYUxQTUpsRGs2bnNuNnlRc0J2egpvWHBJbWlkblVnQWNydmxMSFFSMTRaSHU3dEFaVmh5blFJTGNJRjhaUnpvYnhpclNPM0ZVUkhpMFZPaHRWMUpaCi93NzhwNVhWZ3NYT2ozUmliWm9qUkdUT2w1b0xlUHBaT0xueHZoYkNaMjBmV2FBaHliMlhNSzZiQmR6ckZUbWUKR2VPdGFUWEt2UTE3cXJZTjVKVTVKQ0JhaWFRbjEyZjA1c3E2U0NtUVJVRWxpVmQ1VERiNS9ydVpZUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMnB4VHVwNHVHTHN5VDVrVEF6V2tkaVNJS2djT05NOTFTcUtXbkIza3V6S1orNS9aCkdiT1MrWElGV3IrbEdtbkZnMUY0Sng5Y29vcjQrT0pOcFJYd2k0SWR6OC9FWWVsZTRyZTVuMTd6eW9QcUtYUEYKemdjM1pOc2d0Ni9WQm5ENVBYaUlvc3pEcjR0L1FBaHdIUDRWNXJOQitNQkduN20zMlpjVTE1OUVqTmw5UmNBaApNZHJWKzAvRVZNN1ZGVThVVnhzZWV1c1RCUG9MMk5qdnB6TU1jRVN4WmxjeVVLWWk0blNqa1dHdk5KdmNrUENpCjFHaUhUc1lZZE1qKzRFQTZmZnRKRC9IY2syRUJZVVVCaVZ5dG1VQ1FIRkhabmtTQS9rUXBQWkdWWXRjVVNoMHUKbmY4cWwyM2k1RUVsL3M1eTRjSmI0SVdmZjdqelpaT25OakFWVVFJREFRQUJBb0lCQUVGYkpTa1FxMFZYaWNZRQpSSXZjR0t2OVpmdnltZ3V0emlvZkM1bm0wZ0FwTTZIbmV4ZFUrV2E3OE4vZGxiV2MwNkRiMVdrVTFqUCtDa3NXCkZSSjZ5YXhiblNBSXhIUmxPYW5jTlpGdzZMK3R5bTdVSHRubWpHZ0pudkZyanV0YkVSaVFsWURlYU01dGpRQ08KeFQzVnRLU0JDUU1lTUw4RjNmSWVXZXZRd01TK24wUU5TVnQ4R1lLblptVDVJaUQyU2FtcUFLQW1vRW9kc09GRwpDR3JoUm5jL2MydVJGQzhwdms0aFZCWURSTEV1VGhNU3gvY1JRbjhTdTJKaktCNWRndnZXVHVxL3NJSjQzOWwrCncxWUpSZTMreWlXVTF5Y3lCNm5aOG5hT0RRc1RpTnVudkpQd2tvYUF3U3RxZzVYTGtXTXBiUVFKVWo5ZktzaHgKVURpdThVRUNnWUVBOW4xTkE1d0M0clE1RnVQMHZxMXdZKzNsaitSSzZBT0ZVd085VkN0S2FXUGZqT1JsaWxQNwpmSTFpUUc2V2MxbG9kTHVDVjFQZm9icmFyZ3p0M0hJV213dlpnMVRLTldZTVNwTGMzMUhnN0FlMkU2bHZGNnloCmFweU9saDdIRU1NV3Aybm55d0FaSWdWM1EyUWdUNHVIY1lYU3ZpbCtqQmVWZUQ4NzlJM1dXVmtDZ1lFQTR3dW4KUk80QmwyTjByNXJhRXJoTVRjT2QwYXFxV29lYWpEMHhIaXVTRWlRTytqYU1HU2theWNURzQ4UGc3Vk1LaTVPNQpiN1dydVJ3NFVNVFRaK3ZGRTRURjdDR0lBcmJ2bEhPRExxaDRJeWQyY1BJcEtQc2xpZ1F3VDhKUkt0VmtoVXNoCnpPRTgreHgvVXBzQ1NpVU14S3Z0aGZFcW5IK0ZhR3NiYW85aEpMa0NnWUVBcDA2OXE2bUZ1K09nckl6bVgxYlMKWnNIZmhCL3RTRGE3bEhHQlhWUlZHZHdVclVtS01xNTJrVUJXWkcycjZYZlNrd21EbTBydkRKUU1Rdis3cEZvOApSZGx4TnRlaXVVUWZLNjhzQk5sSzFtc1ZoNXNHTVFlWU9Ra3pMMnFNckMvL2ZIdENQbVErcXYwU3lzZDN0d1o2ClZQQUU3OWF5Y3R5L00vT1grcE1iMzJFQ2dZQkRhcjVzVlUvYnFBaUo3QzA4eWNTK2dvdG1Lb3NTL3BrQmMxb1cKWDFHc1dWQ3BNM0UrTjFwZzl6RW5pSTVOYWc4RGl3WFJDZHpIeG4xaVhrOTMyQ1pZdVdBYjBZa1ZaVVNXakFZego0SXByeGRnQmlhWjNLTHZvMDMyVThWb3dvZFNMVDlmbGdpd2RWRVRxUG1UYnAweTNTV1hxRThaWFdmWS9IeTZ3CjRZb3k0UUtCZ0ZvYmJHdVBhQ0QwT044dmk3TnhGZStzbGNEWlBOTWgydXRZRWFwQnpsTkNDNFB2eXFuTjlTdDgKLzhJSmRVc0M3MVNJYU4zZWJWQmUzKzdieFk0MzVwN0hEVXlGdkRQbTJnOHUvelVPbHU5SzNjZXVQRExJcDVoOAp1MG9oaHFFZUN5cHRFcDFBM1hTNGFRaVlsb3NUTkxrenlKRXM5cnh0aWdHT3ZoOXZKVjRtCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
|
||||
observedCSRExpirationSeconds: 1000000000
|
||||
observedGeneration: 1
|
||||
phase: Active
|
||||
- apiVersion: user.sealos.io/v1
|
||||
kind: UserGroup
|
||||
metadata:
|
||||
annotations:
|
||||
user.sealos.io/creator: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
user.sealos.io/display-name: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
creationTimestamp: "2022-09-14T14:52:02Z"
|
||||
finalizers:
|
||||
- sealos.io/user.group.finalizers
|
||||
generation: 1
|
||||
name: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
ownerReferences:
|
||||
- apiVersion: user.sealos.io/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: User
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
uid: 48a7d9e6-5d15-4b26-923c-667d7b8c429f
|
||||
resourceVersion: "416046"
|
||||
uid: c0b1faf8-3cc4-4817-bd28-e508eb3ab0f4
|
||||
status:
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: user group has been initialized
|
||||
reason: Initialized
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync owner ug user binding successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: OwnerUGUserBindingSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: UserGroup is available now
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
observedGeneration: 1
|
||||
phase: Active
|
||||
- apiVersion: user.sealos.io/v1
|
||||
kind: UserGroupBinding
|
||||
metadata:
|
||||
annotations:
|
||||
user.sealos.io/creator: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
creationTimestamp: "2022-09-14T14:52:02Z"
|
||||
finalizers:
|
||||
- sealos.io/user.group.binding.finalizers
|
||||
generation: 1
|
||||
labels:
|
||||
user.sealos.io/usergroup.name: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
user.sealos.io/usergroup.role: user
|
||||
user.sealos.io/usergroupbinding.kind: namespace
|
||||
user.sealos.io/usergroupbinding.name: ns-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
name: ugn-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
ownerReferences:
|
||||
- apiVersion: user.sealos.io/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: User
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
uid: 48a7d9e6-5d15-4b26-923c-667d7b8c429f
|
||||
resourceVersion: "422287"
|
||||
uid: 3ac62863-d9a1-4159-bc45-fe4c71d691de
|
||||
roleRef: user
|
||||
status:
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: user group binding has been initialized
|
||||
reason: Initialized
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync ug namespace successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: UGNamespaceSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync ug namespace binding successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: UGNamespaceBindingSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: UserGroupBinding is available now
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
observedGeneration: 1
|
||||
phase: Active
|
||||
subject:
|
||||
kind: Namespace
|
||||
name: ns-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
userGroupRef: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
- apiVersion: user.sealos.io/v1
|
||||
kind: UserGroupBinding
|
||||
metadata:
|
||||
annotations:
|
||||
user.sealos.io/creator: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
creationTimestamp: "2022-09-14T14:52:02Z"
|
||||
finalizers:
|
||||
- sealos.io/user.group.binding.finalizers
|
||||
generation: 1
|
||||
labels:
|
||||
user.sealos.io/usergroup.name: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
user.sealos.io/usergroup.role: user
|
||||
user.sealos.io/usergroupbinding.kind: user
|
||||
user.sealos.io/usergroupbinding.name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
name: ugu-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
ownerReferences:
|
||||
- apiVersion: user.sealos.io/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: UserGroup
|
||||
name: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
uid: c0b1faf8-3cc4-4817-bd28-e508eb3ab0f4
|
||||
resourceVersion: "419386"
|
||||
uid: b6cbea8a-a248-4bb1-a9ae-30ba39db072f
|
||||
roleRef: user
|
||||
status:
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: user group binding has been initialized
|
||||
reason: Initialized
|
||||
status: "True"
|
||||
type: Initialized
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync ug user binding by owner successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: UGUserBindingSyncReadyByOwner
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync ug user binding successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: UGUserBindingSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: sync ug namespace binding successfully
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: UGNamespaceBindingSyncReady
|
||||
- lastHeartbeatTime: "2022-09-14T14:52:00Z"
|
||||
lastTransitionTime: "2022-09-14T14:52:00Z"
|
||||
message: UserGroupBinding is available now
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
observedGeneration: 1
|
||||
phase: Active
|
||||
subject:
|
||||
apiGroup: user.sealos.io
|
||||
kind: User
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
userGroupRef: ug-f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
kind: List
|
||||
metadata:
|
||||
resourceVersion: ""
|
||||
```
|
||||
|
||||
@@ -20,6 +20,9 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
@@ -34,3 +37,39 @@ var (
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
const (
|
||||
UserAnnotationOwnerKey = "user.sealos.io/creator"
|
||||
UserAnnotationDisplayKey = "user.sealos.io/display-name"
|
||||
)
|
||||
|
||||
const (
|
||||
UgNameLabelKey = "user.sealos.io/usergroup.name"
|
||||
UgRoleLabelKey = "user.sealos.io/usergroup.role"
|
||||
UgBindingKindLabelKey = "user.sealos.io/usergroupbinding.kind"
|
||||
UgBindingNameLabelKey = "user.sealos.io/usergroupbinding.name"
|
||||
)
|
||||
|
||||
func validateAnnotationKeyNotEmpty(meta metav1.ObjectMeta, key string) error {
|
||||
if meta.Annotations[key] == "" {
|
||||
return fmt.Errorf("annotation %s not allow empty", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateLabelKeyNotEmpty(meta metav1.ObjectMeta, key string) error {
|
||||
if meta.Labels[key] == "" {
|
||||
return fmt.Errorf("label %s not allow empty", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initAnnotationAndLabels(meta metav1.ObjectMeta) metav1.ObjectMeta {
|
||||
if meta.Annotations == nil {
|
||||
meta.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
if meta.Labels == nil {
|
||||
meta.Labels = make(map[string]string, 0)
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -115,3 +117,10 @@ type UserList struct {
|
||||
func init() {
|
||||
SchemeBuilder.Register(&User{}, &UserList{})
|
||||
}
|
||||
|
||||
func (r *User) validateCSRExpirationSeconds() error {
|
||||
if r.Spec.CSRExpirationSeconds == 0 {
|
||||
return errors.New("CSRExpirationSeconds is not allowed to be 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2022 labring.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
)
|
||||
|
||||
// log is for logging in this package.
|
||||
var userlog = logf.Log.WithName("user-resource")
|
||||
|
||||
func (r *User) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
|
||||
//+kubebuilder:webhook:path=/mutate-user-sealos-io-v1-user,mutating=true,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=users,verbs=create;update,versions=v1,name=muser.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Defaulter = &User{}
|
||||
|
||||
// Default implements webhook.Defaulter so a webhook will be registered for the type
|
||||
func (r *User) Default() {
|
||||
userlog.Info("default", "name", r.Name)
|
||||
r.ObjectMeta = initAnnotationAndLabels(r.ObjectMeta)
|
||||
if r.Spec.CSRExpirationSeconds == 0 {
|
||||
r.Spec.CSRExpirationSeconds = 7200
|
||||
}
|
||||
if r.Annotations[UserAnnotationDisplayKey] == "" {
|
||||
r.Annotations[UserAnnotationDisplayKey] = r.Name
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
|
||||
//+kubebuilder:webhook:path=/validate-user-sealos-io-v1-user,mutating=false,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=users,verbs=create;update,versions=v1,name=vuser.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Validator = &User{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *User) ValidateCreate() error {
|
||||
userlog.Info("validate create", "name", r.Name)
|
||||
if err := r.validateCSRExpirationSeconds(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationDisplayKey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *User) ValidateUpdate(old runtime.Object) error {
|
||||
userlog.Info("validate update", "name", r.Name)
|
||||
if err := r.validateCSRExpirationSeconds(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationDisplayKey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *User) ValidateDelete() error {
|
||||
userlog.Info("validate delete", "name", r.Name)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2022 labring.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
)
|
||||
|
||||
// log is for logging in this package.
|
||||
var usergrouplog = logf.Log.WithName("usergroup-resource")
|
||||
|
||||
func (r *UserGroup) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
|
||||
//+kubebuilder:webhook:path=/mutate-user-sealos-io-v1-usergroup,mutating=true,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=usergroups,verbs=create;update,versions=v1,name=musergroup.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Defaulter = &UserGroup{}
|
||||
|
||||
// Default implements webhook.Defaulter so a webhook will be registered for the type
|
||||
func (r *UserGroup) Default() {
|
||||
usergrouplog.Info("default", "name", r.Name)
|
||||
r.ObjectMeta = initAnnotationAndLabels(r.ObjectMeta)
|
||||
if r.Annotations[UserAnnotationDisplayKey] == "" {
|
||||
r.Annotations[UserAnnotationDisplayKey] = r.Name
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
|
||||
//+kubebuilder:webhook:path=/validate-user-sealos-io-v1-usergroup,mutating=false,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=usergroups,verbs=create;update,versions=v1,name=vusergroup.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Validator = &UserGroup{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroup) ValidateCreate() error {
|
||||
usergrouplog.Info("validate create", "name", r.Name)
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationDisplayKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationOwnerKey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroup) ValidateUpdate(old runtime.Object) error {
|
||||
usergrouplog.Info("validate update", "name", r.Name)
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationDisplayKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationOwnerKey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroup) ValidateDelete() error {
|
||||
usergrouplog.Info("validate delete", "name", r.Name)
|
||||
|
||||
// TODO(user): fill in your validation logic upon object deletion.
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright 2022 labring.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
)
|
||||
|
||||
// log is for logging in this package.
|
||||
var usergroupbindinglog = logf.Log.WithName("usergroupbinding-resource")
|
||||
|
||||
func (r *UserGroupBinding) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
|
||||
//+kubebuilder:webhook:path=/mutate-user-sealos-io-v1-usergroupbinding,mutating=true,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=usergroupbindings,verbs=create;update,versions=v1,name=musergroupbinding.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Defaulter = &UserGroupBinding{}
|
||||
|
||||
// Default implements webhook.Defaulter so a webhook will be registered for the type
|
||||
func (r *UserGroupBinding) Default() {
|
||||
usergroupbindinglog.Info("default", "name", r.Name)
|
||||
r.ObjectMeta = initAnnotationAndLabels(r.ObjectMeta)
|
||||
if r.RoleRef == "" {
|
||||
r.RoleRef = RoleRefTypeUser
|
||||
}
|
||||
r.Labels[UgNameLabelKey] = r.UserGroupRef
|
||||
r.Labels[UgRoleLabelKey] = string(r.RoleRef)
|
||||
r.Labels[UgBindingKindLabelKey] = strings.ToLower(r.Subject.Kind)
|
||||
r.Labels[UgBindingNameLabelKey] = strings.ToLower(r.Subject.Name)
|
||||
}
|
||||
|
||||
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
|
||||
//+kubebuilder:webhook:path=/validate-user-sealos-io-v1-usergroupbinding,mutating=false,failurePolicy=fail,sideEffects=None,groups=user.sealos.io,resources=usergroupbindings,verbs=create;update,versions=v1,name=vusergroupbinding.kb.io,admissionReviewVersions=v1
|
||||
|
||||
var _ webhook.Validator = &UserGroupBinding{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroupBinding) ValidateCreate() error {
|
||||
usergroupbindinglog.Info("validate create", "name", r.Name)
|
||||
if err := r.validateWebhook(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroupBinding) ValidateUpdate(old runtime.Object) error {
|
||||
usergroupbindinglog.Info("validate update", "name", r.Name)
|
||||
if err := r.validateWebhook(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *UserGroupBinding) ValidateDelete() error {
|
||||
usergroupbindinglog.Info("validate delete", "name", r.Name)
|
||||
|
||||
// TODO(user): fill in your validation logic upon object deletion.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserGroupBinding) validateWebhook() error {
|
||||
if err := validateAnnotationKeyNotEmpty(r.ObjectMeta, UserAnnotationOwnerKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateLabelKeyNotEmpty(r.ObjectMeta, UgNameLabelKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateLabelKeyNotEmpty(r.ObjectMeta, UgRoleLabelKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateLabelKeyNotEmpty(r.ObjectMeta, UgBindingKindLabelKey); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateLabelKeyNotEmpty(r.ObjectMeta, UgBindingNameLabelKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.RoleRef == "" {
|
||||
return errors.New("roleRef is not allowed to be empty")
|
||||
}
|
||||
if r.UserGroupRef == "" {
|
||||
return errors.New("userGroupRef not allow empty")
|
||||
}
|
||||
if r.Subject.Kind == "" {
|
||||
return errors.New("subject.kind not allow empty")
|
||||
}
|
||||
if r.Subject.Name == "" {
|
||||
return errors.New("subject.name not allow empty")
|
||||
}
|
||||
if r.Subject.APIGroup == "" && r.Subject.Kind != "Namespace" {
|
||||
return errors.New("subject.name not allow empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright 2022 labring.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||
//+kubebuilder:scaffold:imports
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var k8sClient client.Client
|
||||
var testEnv *envtest.Environment
|
||||
var ctx context.Context
|
||||
var cancel context.CancelFunc
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecsWithDefaultAndCustomReporters(t,
|
||||
"Webhook Suite",
|
||||
[]Reporter{printer.NewlineReporter{}})
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
|
||||
|
||||
ctx, cancel = context.WithCancel(context.TODO())
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
|
||||
ErrorIfCRDPathMissing: false,
|
||||
WebhookInstallOptions: envtest.WebhookInstallOptions{
|
||||
Paths: []string{filepath.Join("..", "..", "config", "webhook")},
|
||||
},
|
||||
}
|
||||
|
||||
cfg, err := testEnv.Start()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
err = AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = admissionv1beta1.AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = admissionv1beta1.AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = admissionv1beta1.AddToScheme(scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(k8sClient).NotTo(BeNil())
|
||||
|
||||
// start webhook server using Manager
|
||||
webhookInstallOptions := &testEnv.WebhookInstallOptions
|
||||
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Host: webhookInstallOptions.LocalServingHost,
|
||||
Port: webhookInstallOptions.LocalServingPort,
|
||||
CertDir: webhookInstallOptions.LocalServingCertDir,
|
||||
LeaderElection: false,
|
||||
MetricsBindAddress: "0",
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = (&User{}).SetupWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = (&UserGroup{}).SetupWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = (&UserGroupBinding{}).SetupWebhookWithManager(mgr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
//+kubebuilder:scaffold:webhook
|
||||
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
err = mgr.Start(ctx)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}()
|
||||
|
||||
// wait for the webhook server to get ready
|
||||
dialer := &net.Dialer{Timeout: time.Second}
|
||||
addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort)
|
||||
Eventually(func() error {
|
||||
conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn.Close()
|
||||
return nil
|
||||
}).Should(Succeed())
|
||||
|
||||
}, 60)
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
cancel()
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
@@ -22,7 +22,7 @@ limitations under the License.
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# The following manifests contain a self-signed issuer CR and a certificate CR.
|
||||
# More document can be found at https://docs.cert-manager.io
|
||||
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: selfsigned-issuer
|
||||
namespace: system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
|
||||
namespace: system
|
||||
spec:
|
||||
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
|
||||
dnsNames:
|
||||
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
|
||||
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: selfsigned-issuer
|
||||
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
|
||||
@@ -0,0 +1,5 @@
|
||||
resources:
|
||||
- certificate.yaml
|
||||
|
||||
configurations:
|
||||
- kustomizeconfig.yaml
|
||||
@@ -0,0 +1,16 @@
|
||||
# This configuration is for teaching kustomize how to update name ref and var substitution
|
||||
nameReference:
|
||||
- kind: Issuer
|
||||
group: cert-manager.io
|
||||
fieldSpecs:
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/issuerRef/name
|
||||
|
||||
varReference:
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/commonName
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/dnsNames
|
||||
@@ -13,62 +13,62 @@ namePrefix: user-
|
||||
# someName: someValue
|
||||
|
||||
bases:
|
||||
- ../crd
|
||||
- ../rbac
|
||||
- ../manager
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- ../webhook
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||
#- ../certmanager
|
||||
- ../crd
|
||||
- ../rbac
|
||||
- ../manager
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
- ../webhook
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||
- ../certmanager
|
||||
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
|
||||
#- ../prometheus
|
||||
|
||||
patchesStrategicMerge:
|
||||
# Protect the /metrics endpoint by putting it behind auth.
|
||||
# If you want your controller-manager to expose the /metrics
|
||||
# endpoint w/o any authn/z, please comment the following line.
|
||||
- manager_auth_proxy_patch.yaml
|
||||
# Protect the /metrics endpoint by putting it behind auth.
|
||||
# If you want your controller-manager to expose the /metrics
|
||||
# endpoint w/o any authn/z, please comment the following line.
|
||||
- manager_auth_proxy_patch.yaml
|
||||
|
||||
# Mount the controller config file for loading manager configurations
|
||||
# through a ComponentConfig type
|
||||
#- manager_config_patch.yaml
|
||||
# Mount the controller config file for loading manager configurations
|
||||
# through a ComponentConfig type
|
||||
#- manager_config_patch.yaml
|
||||
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- manager_webhook_patch.yaml
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
- manager_webhook_patch.yaml
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
|
||||
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
|
||||
# 'CERTMANAGER' needs to be enabled to use ca injection
|
||||
#- webhookcainjection_patch.yaml
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
|
||||
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
|
||||
# 'CERTMANAGER' needs to be enabled to use ca injection
|
||||
- webhookcainjection_patch.yaml
|
||||
|
||||
# the following config is for teaching kustomize how to do var substitution
|
||||
vars:
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
|
||||
# objref:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
# fieldref:
|
||||
# fieldpath: metadata.namespace
|
||||
#- name: CERTIFICATE_NAME
|
||||
# objref:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
#- name: SERVICE_NAMESPACE # namespace of the service
|
||||
# objref:
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
# fieldref:
|
||||
# fieldpath: metadata.namespace
|
||||
#- name: SERVICE_NAME
|
||||
# objref:
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||
- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
|
||||
objref:
|
||||
kind: Certificate
|
||||
group: cert-manager.io
|
||||
version: v1
|
||||
name: serving-cert # this name should match the one in certificate.yaml
|
||||
fieldref:
|
||||
fieldpath: metadata.namespace
|
||||
- name: CERTIFICATE_NAME
|
||||
objref:
|
||||
kind: Certificate
|
||||
group: cert-manager.io
|
||||
version: v1
|
||||
name: serving-cert # this name should match the one in certificate.yaml
|
||||
- name: SERVICE_NAMESPACE # namespace of the service
|
||||
objref:
|
||||
kind: Service
|
||||
version: v1
|
||||
name: webhook-service
|
||||
fieldref:
|
||||
fieldpath: metadata.namespace
|
||||
- name: SERVICE_NAME
|
||||
objref:
|
||||
kind: Service
|
||||
version: v1
|
||||
name: webhook-service
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
@@ -0,0 +1,15 @@
|
||||
# This patch add annotation to admission webhook config and
|
||||
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
name: mutating-webhook-configuration
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: validating-webhook-configuration
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
@@ -39,6 +39,7 @@ spec:
|
||||
args:
|
||||
- --leader-elect
|
||||
image: controller:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: manager
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -68,19 +69,3 @@ spec:
|
||||
memory: 64Mi
|
||||
serviceAccountName: controller-manager
|
||||
terminationGracePeriodSeconds: 10
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: controller-manager-api-service
|
||||
namespace: system
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8088
|
||||
protocol: TCP
|
||||
targetPort: 8088
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
|
||||
@@ -3,5 +3,4 @@ kind: User
|
||||
metadata:
|
||||
name: f8699ded-58d3-432b-a9ff-56568b57a38d
|
||||
spec:
|
||||
displayName: cuisongliu
|
||||
csrExpirationSeconds: 1000000000
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
resources:
|
||||
- manifests.yaml
|
||||
- service.yaml
|
||||
|
||||
configurations:
|
||||
- kustomizeconfig.yaml
|
||||
@@ -0,0 +1,25 @@
|
||||
# the following config is for teaching kustomize where to look at when substituting vars.
|
||||
# It requires kustomize v2.1.0 or newer to work properly.
|
||||
nameReference:
|
||||
- kind: Service
|
||||
version: v1
|
||||
fieldSpecs:
|
||||
- kind: MutatingWebhookConfiguration
|
||||
group: admissionregistration.k8s.io
|
||||
path: webhooks/clientConfig/service/name
|
||||
- kind: ValidatingWebhookConfiguration
|
||||
group: admissionregistration.k8s.io
|
||||
path: webhooks/clientConfig/service/name
|
||||
|
||||
namespace:
|
||||
- kind: MutatingWebhookConfiguration
|
||||
group: admissionregistration.k8s.io
|
||||
path: webhooks/clientConfig/service/namespace
|
||||
create: true
|
||||
- kind: ValidatingWebhookConfiguration
|
||||
group: admissionregistration.k8s.io
|
||||
path: webhooks/clientConfig/service/namespace
|
||||
create: true
|
||||
|
||||
varReference:
|
||||
- path: metadata/annotations
|
||||
@@ -0,0 +1,134 @@
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: mutating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /mutate-user-sealos-io-v1-user
|
||||
failurePolicy: Fail
|
||||
name: muser.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- users
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /mutate-user-sealos-io-v1-usergroup
|
||||
failurePolicy: Fail
|
||||
name: musergroup.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroups
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /mutate-user-sealos-io-v1-usergroupbinding
|
||||
failurePolicy: Fail
|
||||
name: musergroupbinding.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroupbindings
|
||||
sideEffects: None
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: validating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /validate-user-sealos-io-v1-user
|
||||
failurePolicy: Fail
|
||||
name: vuser.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- users
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /validate-user-sealos-io-v1-usergroup
|
||||
failurePolicy: Fail
|
||||
name: vusergroup.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroups
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /validate-user-sealos-io-v1-usergroupbinding
|
||||
failurePolicy: Fail
|
||||
name: vusergroupbinding.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroupbindings
|
||||
sideEffects: None
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright 2022 cuisongliu@qq.com.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
userv1 "github.com/labring/sealos/controllers/user/api/v1"
|
||||
"github.com/labring/sealos/controllers/user/controllers/helper"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
Logger logr.Logger
|
||||
client.Client
|
||||
}
|
||||
|
||||
func NewCache(cli client.Client, logger logr.Logger) *Cache {
|
||||
return &Cache{
|
||||
Logger: logger,
|
||||
Client: cli,
|
||||
}
|
||||
}
|
||||
|
||||
func SetupCache(mgr ctrl.Manager) error {
|
||||
ugb := &userv1.UserGroupBinding{}
|
||||
ugRefFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).UserGroupRef}
|
||||
}
|
||||
subjectKindFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).Subject.Kind}
|
||||
}
|
||||
subjectNameFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).Subject.Name}
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "userGroupRef", ugRefFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "subject.kind", subjectKindFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "subject.name", subjectNameFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Cache) FetchNamespaceFromUserGroup(ctx context.Context, userGroup string) (namespaces []userv1.UserGroupBinding) {
|
||||
ugUserBindingList := make([]userv1.UserGroupBindingList, 0)
|
||||
var ugUserBinding userv1.UserGroupBindingList
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"userGroupRef": userGroup}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "userGroupRef", userGroup)
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.kind": "Namespace"}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.kind", "User")
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
|
||||
var newAny helper.Any
|
||||
|
||||
for i, item := range ugUserBindingList {
|
||||
newIAny := helper.NewAny(nil)
|
||||
for _, j := range item.Items {
|
||||
newIAny = newIAny.InsertValue(j.Name, j)
|
||||
}
|
||||
if i == 0 {
|
||||
newAny = newIAny
|
||||
}
|
||||
newAny = newAny.Intersection(newIAny)
|
||||
}
|
||||
values := newAny.ListValue()
|
||||
for _, value := range values {
|
||||
if ns, ok := value.(userv1.UserGroupBinding); ok {
|
||||
namespaces = append(namespaces, ns)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Cache) FetchUserFromUserGroup(ctx context.Context, userGroup string) (users []userv1.UserGroupBinding) {
|
||||
ugUserBindingList := make([]userv1.UserGroupBindingList, 0)
|
||||
var ugUserBinding userv1.UserGroupBindingList
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"userGroupRef": userGroup}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "userGroupRef", userGroup)
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.kind": "User"}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.kind", "User")
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
|
||||
var newAny helper.Any
|
||||
|
||||
for i, item := range ugUserBindingList {
|
||||
newIAny := helper.NewAny(nil)
|
||||
for _, j := range item.Items {
|
||||
newIAny = newIAny.InsertValue(j.Name, j)
|
||||
}
|
||||
if i == 0 {
|
||||
newAny = newIAny
|
||||
}
|
||||
newAny = newAny.Intersection(newIAny)
|
||||
}
|
||||
values := newAny.ListValue()
|
||||
for _, value := range values {
|
||||
if u, ok := value.(userv1.UserGroupBinding); ok {
|
||||
users = append(users, u)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Cache) FetchUserGroupFromUser(ctx context.Context, user string) (userGroups []userv1.UserGroupBinding) {
|
||||
ugUserBindingList := make([]userv1.UserGroupBindingList, 0)
|
||||
var ugUserBinding userv1.UserGroupBindingList
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.name": user}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.name", user)
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.kind": "User"}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.kind", "User")
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
|
||||
var newAny helper.Any
|
||||
|
||||
for i, item := range ugUserBindingList {
|
||||
newIAny := helper.NewAny(nil)
|
||||
for _, j := range item.Items {
|
||||
newIAny = newIAny.InsertValue(j.Name, j)
|
||||
}
|
||||
if i == 0 {
|
||||
newAny = newIAny
|
||||
}
|
||||
newAny = newAny.Intersection(newIAny)
|
||||
}
|
||||
values := newAny.ListValue()
|
||||
for _, value := range values {
|
||||
if u, ok := value.(userv1.UserGroupBinding); ok {
|
||||
userGroups = append(userGroups, u)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -48,7 +48,8 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
)
|
||||
|
||||
const userAnnotationOwnerKey = "user.sealos.io/creator"
|
||||
var userAnnotationOwnerKey = userv1.UserAnnotationOwnerKey
|
||||
|
||||
const clusterRoleByCreate = "sealos-user-create-role"
|
||||
|
||||
const clusterRoleByManager = "sealos-user-manager-role"
|
||||
|
||||
@@ -94,38 +94,11 @@ func (r *UserGroupBindingReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
}
|
||||
r.Scheme = mgr.GetScheme()
|
||||
r.cache = mgr.GetCache()
|
||||
if err := r.InstallCache(mgr); err != nil {
|
||||
return err
|
||||
}
|
||||
r.Logger.V(1).Info("init reconcile controller user group binding")
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&userv1.UserGroupBinding{}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *UserGroupBindingReconciler) InstallCache(mgr ctrl.Manager) error {
|
||||
ugb := &userv1.UserGroupBinding{}
|
||||
ugRefFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).UserGroupRef}
|
||||
}
|
||||
subjectKindFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).Subject.Kind}
|
||||
}
|
||||
subjectNameFunc := func(obj client.Object) []string {
|
||||
return []string{obj.(*userv1.UserGroupBinding).Subject.Name}
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "userGroupRef", ugRefFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "subject.kind", subjectKindFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), ugb, "subject.name", subjectNameFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserGroupBindingReconciler) updateStatus(ctx context.Context, nn types.NamespacedName, status *userv1.UserGroupBindingStatus) error {
|
||||
if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
original := &userv1.UserGroupBinding{}
|
||||
|
||||
@@ -19,6 +19,8 @@ package controllers
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/labring/sealos/controllers/user/controllers/cache"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -109,39 +111,6 @@ func (r *UserGroupNamespaceBindingController) syncNamespace(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserGroupNamespaceBindingController) mergeFromUser(ctx context.Context, ugBinding *userv1.UserGroupBinding) (users []userv1.UserGroupBinding) {
|
||||
ugUserBindingList := make([]userv1.UserGroupBindingList, 0)
|
||||
var ugUserBinding userv1.UserGroupBindingList
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"userGroupRef": ugBinding.UserGroupRef}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "userGroupRef", ugBinding.UserGroupRef)
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.kind": "User"}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.kind", "User")
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
|
||||
var newAny helper.Any
|
||||
|
||||
for i, item := range ugUserBindingList {
|
||||
newIAny := helper.NewAny(nil)
|
||||
for _, j := range item.Items {
|
||||
newIAny = newIAny.InsertValue(j.Name, j)
|
||||
}
|
||||
if i == 0 {
|
||||
newAny = newIAny
|
||||
}
|
||||
newAny = newAny.Intersection(newIAny)
|
||||
}
|
||||
values := newAny.ListValue()
|
||||
for _, value := range values {
|
||||
if u, ok := value.(userv1.UserGroupBinding); ok {
|
||||
users = append(users, u)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *UserGroupNamespaceBindingController) syncRoleBinding(ctx context.Context, ugBinding *userv1.UserGroupBinding) {
|
||||
roleBindingConditionType := userv1.ConditionType("UGNamespaceBindingSyncReady")
|
||||
condition := &userv1.Condition{
|
||||
@@ -152,7 +121,7 @@ func (r *UserGroupNamespaceBindingController) syncRoleBinding(ctx context.Contex
|
||||
Reason: string(userv1.Ready),
|
||||
Message: "sync ug namespace binding successfully",
|
||||
}
|
||||
users := r.mergeFromUser(ctx, ugBinding)
|
||||
users := cache.NewCache(r.Client, r.Logger).FetchUserFromUserGroup(ctx, ugBinding.UserGroupRef)
|
||||
defer r.saveCondition(ugBinding, condition)
|
||||
userName := ugBinding.Annotations[userAnnotationOwnerKey]
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ package controllers
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/labring/sealos/controllers/user/controllers/cache"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
@@ -172,38 +174,6 @@ func (r *UserGroupUserBindingController) syncClusterRoleBindingByOwner(ctx conte
|
||||
}
|
||||
}
|
||||
}
|
||||
func (r *UserGroupUserBindingController) mergeFromNamespace(ctx context.Context, ugBinding *userv1.UserGroupBinding) (users []userv1.UserGroupBinding) {
|
||||
ugUserBindingList := make([]userv1.UserGroupBindingList, 0)
|
||||
var ugUserBinding userv1.UserGroupBindingList
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"userGroupRef": ugBinding.UserGroupRef}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "userGroupRef", ugBinding.UserGroupRef)
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
if err := r.List(ctx, &ugUserBinding, client.MatchingFields{"subject.kind": "Namespace"}); err != nil {
|
||||
r.Logger.Error(err, "list ugUserBinding error from cache", "subject.kind", "User")
|
||||
}
|
||||
ugUserBindingList = append(ugUserBindingList, ugUserBinding)
|
||||
|
||||
var newAny helper.Any
|
||||
|
||||
for i, item := range ugUserBindingList {
|
||||
newIAny := helper.NewAny(nil)
|
||||
for _, j := range item.Items {
|
||||
newIAny = newIAny.InsertValue(j.Name, j)
|
||||
}
|
||||
if i == 0 {
|
||||
newAny = newIAny
|
||||
}
|
||||
newAny = newAny.Intersection(newIAny)
|
||||
}
|
||||
values := newAny.ListValue()
|
||||
for _, value := range values {
|
||||
if u, ok := value.(userv1.UserGroupBinding); ok {
|
||||
users = append(users, u)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *UserGroupUserBindingController) syncRoleBinding(ctx context.Context, ugBinding *userv1.UserGroupBinding) {
|
||||
roleBindingConditionType := userv1.ConditionType("UGNamespaceBindingSyncReady")
|
||||
@@ -215,7 +185,8 @@ func (r *UserGroupUserBindingController) syncRoleBinding(ctx context.Context, ug
|
||||
Reason: string(userv1.Ready),
|
||||
Message: "sync ug namespace binding successfully",
|
||||
}
|
||||
namespaces := r.mergeFromNamespace(ctx, ugBinding)
|
||||
|
||||
namespaces := cache.NewCache(r.Client, r.Logger).FetchNamespaceFromUserGroup(ctx, ugBinding.UserGroupRef)
|
||||
defer r.saveCondition(ugBinding, condition)
|
||||
userName := ugBinding.Annotations[userAnnotationOwnerKey]
|
||||
|
||||
|
||||
@@ -826,22 +826,6 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: user-controller-manager-api-service
|
||||
namespace: user-system
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8088
|
||||
protocol: TCP
|
||||
targetPort: 8088
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
@@ -856,6 +840,19 @@ spec:
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -876,6 +873,47 @@ spec:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --health-probe-bind-address=:8081
|
||||
- --metrics-bind-address=127.0.0.1:8080
|
||||
- --leader-elect
|
||||
command:
|
||||
- /manager
|
||||
image: ghcr.io/labring/user-controller:dev
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
@@ -899,39 +937,170 @@ spec:
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
- args:
|
||||
- --health-probe-bind-address=:8081
|
||||
- --metrics-bind-address=127.0.0.1:8080
|
||||
- --leader-elect
|
||||
command:
|
||||
- /manager
|
||||
image: ghcr.io/labring/user-controller:dev
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
name: manager
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
serviceAccountName: user-controller-manager
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: user-serving-cert
|
||||
namespace: user-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- user-webhook-service.user-system.svc
|
||||
- user-webhook-service.user-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: user-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: user-selfsigned-issuer
|
||||
namespace: user-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: user-system/user-serving-cert
|
||||
name: user-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /mutate-user-sealos-io-v1-user
|
||||
failurePolicy: Fail
|
||||
name: muser.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- users
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /mutate-user-sealos-io-v1-usergroup
|
||||
failurePolicy: Fail
|
||||
name: musergroup.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroups
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /mutate-user-sealos-io-v1-usergroupbinding
|
||||
failurePolicy: Fail
|
||||
name: musergroupbinding.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroupbindings
|
||||
sideEffects: None
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: user-system/user-serving-cert
|
||||
name: user-validating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /validate-user-sealos-io-v1-user
|
||||
failurePolicy: Fail
|
||||
name: vuser.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- users
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /validate-user-sealos-io-v1-usergroup
|
||||
failurePolicy: Fail
|
||||
name: vusergroup.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroups
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: user-webhook-service
|
||||
namespace: user-system
|
||||
path: /validate-user-sealos-io-v1-usergroupbinding
|
||||
failurePolicy: Fail
|
||||
name: vusergroupbinding.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- user.sealos.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- usergroupbindings
|
||||
sideEffects: None
|
||||
|
||||
+30
-26
@@ -20,15 +20,16 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
"github.com/labring/sealos/controllers/user/controllers/cache"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
@@ -120,6 +121,25 @@ func main() {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "Payment")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err = cache.SetupCache(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to cache controller")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err = (&userv1.User{}).SetupWebhookWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create webhook", "webhook", "User")
|
||||
os.Exit(1)
|
||||
}
|
||||
setupLog.Info("add ug and ugb webhooks")
|
||||
if err = (&userv1.UserGroup{}).SetupWebhookWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create webhook", "webhook", "UserGroup")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err = (&userv1.UserGroupBinding{}).SetupWebhookWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create webhook", "webhook", "UserGroupBinding")
|
||||
os.Exit(1)
|
||||
}
|
||||
//+kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||
@@ -132,25 +152,9 @@ func main() {
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
go func() {
|
||||
setupLog.Info("starting manager")
|
||||
if err := mgr.Start(ctx); err != nil {
|
||||
setupLog.Error(err, "failed to running manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
if mgr.GetCache().WaitForCacheSync(context.Background()) {
|
||||
done <- struct{}{}
|
||||
}
|
||||
}()
|
||||
<-done
|
||||
go func(mgr ctrl.Manager) {
|
||||
//TODO add apiserver
|
||||
}(mgr)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
wg.Wait()
|
||||
setupLog.Info("starting manager")
|
||||
if err = mgr.Start(ctx); err != nil {
|
||||
setupLog.Error(err, "failed to running manager")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user