Skip to content

Commit

Permalink
webhook refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Eikykun authored and shaofan-hs committed Aug 17, 2023
1 parent abc9ea7 commit 0b61e50
Show file tree
Hide file tree
Showing 14 changed files with 437 additions and 291 deletions.
31 changes: 31 additions & 0 deletions pkg/utils/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2023 The KusionStack Authors.
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 utils

import (
"sigs.k8s.io/controller-runtime/pkg/client"

"kusionstack.io/kafed/apis/apps/v1alpha1"
)

func ControlledByKafed(obj client.Object) bool {
if obj == nil || obj.GetLabels() == nil {
return false
}
v, ok := obj.GetLabels()[v1alpha1.KafedSystemLabel]
return ok && v == "true"
}
3 changes: 1 addition & 2 deletions pkg/webhook/admission/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

"k8s.io/apimachinery/pkg/runtime"

"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

Expand All @@ -42,5 +41,5 @@ type ValidationFunc func(ctx context.Context, req admission.Request, obj runtime
type MutationFunc func(ctx context.Context, req admission.Request, obj runtime.Object) error

type DispatchHandler interface {
Handle(context.Context, admission.Request, client.Client, *admission.Decoder) admission.Response
Handle(context.Context, admission.Request) admission.Response
}
37 changes: 0 additions & 37 deletions pkg/webhook/server/add_generic.go

This file was deleted.

12 changes: 11 additions & 1 deletion pkg/webhook/server/generic/generic_mutating_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (h *MutatingHandler) Handle(ctx context.Context, req admission.Request) (re
key = fmt.Sprintf("%s/%s", req.Kind.Kind, req.SubResource)
}
if handler, exist := MutatingTypeHandlerMap[key]; exist {
return handler.Handle(ctx, req, h.Client, h.Decoder)
return handler.Handle(ctx, req)
}

// do nothing
Expand All @@ -54,6 +54,11 @@ var _ inject.Client = &MutatingHandler{}
// InjectClient injects the client into the MutatingHandler
func (h *MutatingHandler) InjectClient(c client.Client) error {
h.Client = c
for i := range MutatingTypeHandlerMap {
if _, err := inject.ClientInto(h.Client, MutatingTypeHandlerMap[i]); err != nil {
return err
}
}
return nil
}

Expand All @@ -62,5 +67,10 @@ var _ admission.DecoderInjector = &MutatingHandler{}
// InjectDecoder injects the decoder into the MutatingHandler
func (h *MutatingHandler) InjectDecoder(d *admission.Decoder) error {
h.Decoder = d
for i := range MutatingTypeHandlerMap {
if _, err := admission.InjectDecoderInto(d, MutatingTypeHandlerMap[i]); err != nil {
return err
}
}
return nil
}
12 changes: 11 additions & 1 deletion pkg/webhook/server/generic/generic_validating_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) (
key = fmt.Sprintf("%s/%s", req.Kind.Kind, req.SubResource)
}
if handler, exist := ValidatingTypeHandlerMap[key]; exist {
return handler.Handle(ctx, req, h.Client, h.Decoder)
return handler.Handle(ctx, req)
}

return admission.ValidationResponse(true, "")
Expand All @@ -50,6 +50,11 @@ var _ inject.Client = &ValidatingHandler{}
// InjectClient injects the client into the ValidatingHandler
func (h *ValidatingHandler) InjectClient(c client.Client) error {
h.Client = c
for i := range MutatingTypeHandlerMap {
if _, err := inject.ClientInto(h.Client, ValidatingTypeHandlerMap[i]); err != nil {
return err
}
}
return nil
}

Expand All @@ -58,5 +63,10 @@ var _ admission.DecoderInjector = &ValidatingHandler{}
// InjectDecoder injects the decoder into the ValidatingHandler
func (h *ValidatingHandler) InjectDecoder(d *admission.Decoder) error {
h.Decoder = d
for i := range MutatingTypeHandlerMap {
if _, err := admission.InjectDecoderInto(d, ValidatingTypeHandlerMap[i]); err != nil {
return err
}
}
return nil
}
7 changes: 7 additions & 0 deletions pkg/webhook/server/generic/generic_webhooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

webhookdmission "kusionstack.io/kafed/pkg/webhook/admission"
"kusionstack.io/kafed/pkg/webhook/server/generic/pod"
)

var (
Expand All @@ -32,3 +33,9 @@ var (

var MutatingTypeHandlerMap = map[string]webhookdmission.DispatchHandler{}
var ValidatingTypeHandlerMap = map[string]webhookdmission.DispatchHandler{}

func init() {
MutatingTypeHandlerMap["Pod"] = pod.NewMutatingHandler()

ValidatingTypeHandlerMap["Pod"] = pod.NewValidatingHandler()
}
151 changes: 151 additions & 0 deletions pkg/webhook/server/generic/pod/opslifecycle/mutating.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
Copyright 2023 The KusionStack Authors.
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 opslifecycle

import (
"context"
"fmt"

admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

"kusionstack.io/kafed/apis/apps/v1alpha1"
"kusionstack.io/kafed/pkg/controllers/podopslifecycle"
"kusionstack.io/kafed/pkg/utils"
)

func (lc *OpsLifecycle) Mutating(ctx context.Context, c client.Client, oldPod, newPod *corev1.Pod, operation admissionv1.Operation) error {
if !utils.ControlledByKafed(newPod) || operation != admissionv1.Update {
return nil
}
addReadinessGates(newPod, v1alpha1.ReadinessGatePodServiceReady)

newIdToLabelsMap, typeToNumsMap, err := podopslifecycle.PodIDAndTypesMap(newPod)
if err != nil {
return err
}

var operatingCount, operateCount, completeCount int
var undoTypeToNumsMap = map[string]int{}
for id, labels := range newIdToLabelsMap {
if undoOperationType, ok := labels[v1alpha1.PodUndoOperationTypeLabelPrefix]; ok { // operation is canceled
if _, ok := undoTypeToNumsMap[undoOperationType]; !ok {
undoTypeToNumsMap[undoOperationType] = 1
} else {
undoTypeToNumsMap[undoOperationType] = undoTypeToNumsMap[undoOperationType] + 1
}

// clean up these labels with id
for _, v := range []string{v1alpha1.PodOperatingLabelPrefix, v1alpha1.PodOperationTypeLabelPrefix, v1alpha1.PodPreCheckLabelPrefix, v1alpha1.PodPreCheckedLabelPrefix, v1alpha1.PodPrepareLabelPrefix, v1alpha1.PodOperateLabelPrefix} {
delete(newPod.Labels, fmt.Sprintf("%s/%s", v, id))
}

delete(newPod.Labels, fmt.Sprintf("%s/%s", v1alpha1.PodUndoOperationTypeLabelPrefix, id))
continue
}

if _, ok := labels[v1alpha1.PodOperatingLabelPrefix]; ok { // operating
operatingCount++

if _, ok := labels[v1alpha1.PodPreCheckedLabelPrefix]; ok {
if _, ok := labels[v1alpha1.PodPrepareLabelPrefix]; !ok {
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodPrepareLabelPrefix, id))
}
if _, ok := labels[v1alpha1.PodOperateLabelPrefix]; !ok {
if ready, _, _ := lc.readyToUpgrade(newPod); ready {
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodOperateLabelPrefix, id))
}
}
} else {
if _, ok := labels[v1alpha1.PodPreCheckLabelPrefix]; !ok {
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodPreCheckLabelPrefix, id))
}
}
}

if _, ok := labels[v1alpha1.PodOperateLabelPrefix]; ok {
operateCount++
continue
}

if _, ok := labels[v1alpha1.PodOperatedLabelPrefix]; ok { // operated
if _, ok := labels[v1alpha1.PodPostCheckedLabelPrefix]; ok {
if _, ok := labels[v1alpha1.PodCompleteLabelPrefix]; !ok {
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodCompleteLabelPrefix, id))
}
} else {
if _, ok := labels[v1alpha1.PodPostCheckLabelPrefix]; !ok {
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodPostCheckLabelPrefix, id))
}
}
}

if _, ok := labels[v1alpha1.PodCompleteLabelPrefix]; ok { // complete
completeCount++
}
}

for t, num := range undoTypeToNumsMap {
if num == typeToNumsMap[t] { // reset the permission with type t if all operating with type t are canceled
delete(newPod.Labels, fmt.Sprintf("%s/%s", v1alpha1.PodOperationPermissionLabelPrefix, t))
}
}

if operatingCount != 0 { // wait for all operatings to be done
return nil
}

if operateCount == len(newIdToLabelsMap) { // all operations are prepared
oldIdToLabelsMap, _, err := podopslifecycle.PodIDAndTypesMap(oldPod)
if err != nil {
return err
}

for id := range newIdToLabelsMap {
for _, v := range []string{v1alpha1.PodPreCheckLabelPrefix, v1alpha1.PodPreCheckedLabelPrefix, v1alpha1.PodPrepareLabelPrefix, v1alpha1.PodOperateLabelPrefix} {
delete(newPod.Labels, fmt.Sprintf("%s/%s", v, id))
}
lc.addLabelWithTime(newPod, fmt.Sprintf("%s/%s", v1alpha1.PodOperatedLabelPrefix, id))

t, ok := oldIdToLabelsMap[id][v1alpha1.PodOperationTypeLabelPrefix]
if !ok {
return fmt.Errorf("pod %s/%s label %s not found", oldPod.Namespace, oldPod.Name, fmt.Sprintf("%s/%s", v1alpha1.PodPreCheckedLabelPrefix, id))
}

delete(newPod.Labels, fmt.Sprintf("%s/%s", v1alpha1.PodOperationPermissionLabelPrefix, t))
newPod.Labels[fmt.Sprintf("%s/%s", v1alpha1.PodDoneOperationTypeLabelPrefix, id)] = t
}
}

if completeCount == len(newIdToLabelsMap) { // all operations are done
satisfied, _, err := lc.satisfyExpectedFinalizers(newPod)
if err != nil {
return err
}
if satisfied { // all operations are done and all expected finalizers are satisfied, then remove all unuseful labels, and add service available label
for id := range newIdToLabelsMap {
for _, v := range []string{v1alpha1.PodOperatedLabelPrefix, v1alpha1.PodDoneOperationTypeLabelPrefix, v1alpha1.PodPostCheckLabelPrefix, v1alpha1.PodPostCheckedLabelPrefix, v1alpha1.PodCompleteLabelPrefix} {
delete(newPod.Labels, fmt.Sprintf("%s/%s", v, id))
}
}
lc.addLabelWithTime(newPod, v1alpha1.PodServiceAvailableLabel)
}
}

return nil
}
Loading

0 comments on commit 0b61e50

Please sign in to comment.