Add webhook for mutating workload object of work resource (#206)
Signed-off-by: changzhen <changzhen5@huawei.com>
This commit is contained in:
parent
5abf32099f
commit
1b0aa972a1
|
|
@ -47,6 +47,20 @@ webhooks:
|
|||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
- name: work.karmada.io
|
||||
rules:
|
||||
- operations: ["CREATE", "UPDATE"]
|
||||
apiGroups: ["work.karmada.io"]
|
||||
apiVersions: ["*"]
|
||||
resources: ["works"]
|
||||
scope: "Namespaced"
|
||||
clientConfig:
|
||||
url: https://karmada-webhook.karmada-system.svc:443/mutate-work
|
||||
caBundle: {{caBundle}}
|
||||
failurePolicy: Fail
|
||||
sideEffects: None
|
||||
admissionReviewVersions: ["v1beta1"]
|
||||
timeoutSeconds: 3
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/karmada-io/karmada/pkg/webhook/clusterpropagationpolicy"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/overridepolicy"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/propagationpolicy"
|
||||
"github.com/karmada-io/karmada/pkg/webhook/work"
|
||||
)
|
||||
|
||||
// NewWebhookCommand creates a *cobra.Command object with default parameters
|
||||
|
|
@ -73,6 +74,7 @@ func Run(opts *options.Options, stopChan <-chan struct{}) error {
|
|||
hookServer.Register("/mutate-clusterpropagationpolicy", &webhook.Admission{Handler: &clusterpropagationpolicy.MutatingAdmission{}})
|
||||
hookServer.Register("/validate-clusterpropagationpolicy", &webhook.Admission{Handler: &clusterpropagationpolicy.ValidatingAdmission{}})
|
||||
hookServer.Register("/mutate-overridepolicy", &webhook.Admission{Handler: &overridepolicy.MutatingAdmission{}})
|
||||
hookServer.Register("/mutate-work", &webhook.Admission{Handler: &work.MutatingAdmission{}})
|
||||
hookServer.WebhookMux.Handle("/readyz/", http.StripPrefix("/readyz/", &healthz.Handler{}))
|
||||
|
||||
// blocks until the stop channel is closed.
|
||||
|
|
|
|||
|
|
@ -155,17 +155,6 @@ func (c *ResourceBindingController) getBindingClusterNames(binding *workv1alpha1
|
|||
return clusterNames
|
||||
}
|
||||
|
||||
// removeIrrelevantField will delete irrelevant field from workload. such as uid, timestamp, status
|
||||
func (c *ResourceBindingController) removeIrrelevantField(workload *unstructured.Unstructured) {
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "creationTimestamp")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "generation")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "resourceVersion")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "selfLink")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "managedFields")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "uid")
|
||||
unstructured.RemoveNestedField(workload.Object, "status")
|
||||
}
|
||||
|
||||
// transformBindingToWorks will transform propagationBinding to Works
|
||||
func (c *ResourceBindingController) transformBindingToWorks(binding *workv1alpha1.ResourceBinding, clusterNames []string) error {
|
||||
dynamicResource, err := restmapper.GetGroupVersionResource(c.RESTMapper,
|
||||
|
|
@ -193,7 +182,6 @@ func (c *ResourceBindingController) transformBindingToWorks(binding *workv1alpha
|
|||
// ensureWork ensure Work to be created or updated
|
||||
func (c *ResourceBindingController) ensureWork(workload *unstructured.Unstructured, clusterNames []string,
|
||||
binding *workv1alpha1.ResourceBinding) error {
|
||||
c.removeIrrelevantField(workload)
|
||||
|
||||
for _, clusterName := range clusterNames {
|
||||
// apply override policies
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ func (c *HorizontalPodAutoscalerController) buildWorks(hpa *autoscalingv1.Horizo
|
|||
return nil
|
||||
}
|
||||
hpaObj := &unstructured.Unstructured{Object: uncastObj}
|
||||
util.RemoveIrrelevantField(hpaObj)
|
||||
for _, clusterName := range clusters {
|
||||
workNamespace, err := names.GenerateExecutionSpaceName(clusterName)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ func (c *Controller) buildWorks(namespace *v1.Namespace, clusters []v1alpha1.Clu
|
|||
return nil
|
||||
}
|
||||
namespaceObj := &unstructured.Unstructured{Object: uncastObj}
|
||||
util.RemoveIrrelevantField(namespaceObj)
|
||||
|
||||
for _, cluster := range clusters {
|
||||
workNamespace, err := names.GenerateExecutionSpaceName(cluster.Name)
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// RemoveIrrelevantField will delete irrelevant field from workload. such as uid, timestamp, status
|
||||
func RemoveIrrelevantField(workload *unstructured.Unstructured) {
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "creationTimestamp")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "generation")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "resourceVersion")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "selfLink")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "managedFields")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "uid")
|
||||
unstructured.RemoveNestedField(workload.Object, "status")
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package work
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
|
||||
)
|
||||
|
||||
// MutatingAdmission mutates API request if necessary.
|
||||
type MutatingAdmission struct {
|
||||
decoder *admission.Decoder
|
||||
}
|
||||
|
||||
// Check if our MutatingAdmission implements necessary interface
|
||||
var _ admission.Handler = &MutatingAdmission{}
|
||||
var _ admission.DecoderInjector = &MutatingAdmission{}
|
||||
|
||||
// Handle yields a response to an AdmissionRequest.
|
||||
func (a *MutatingAdmission) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
work := &workv1alpha1.Work{}
|
||||
|
||||
err := a.decoder.Decode(req, work)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
klog.V(2).Infof("Mutating work(%s) for request: %s", work.Name, req.Operation)
|
||||
|
||||
var manifests []workv1alpha1.Manifest
|
||||
|
||||
for _, manifest := range work.Spec.Workload.Manifests {
|
||||
workloadObj := &unstructured.Unstructured{}
|
||||
err := json.Unmarshal(manifest.Raw, workloadObj)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to unmarshal work(%s) manifest to Unstructured", work.Name)
|
||||
return admission.Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
removeIrrelevantField(workloadObj)
|
||||
|
||||
workloadJSON, err := workloadObj.MarshalJSON()
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to marshal workload of work(%s)", work.Name)
|
||||
return admission.Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
manifests = append(manifests, workv1alpha1.Manifest{RawExtension: runtime.RawExtension{Raw: workloadJSON}})
|
||||
}
|
||||
|
||||
work.Spec.Workload.Manifests = manifests
|
||||
marshaledBytes, err := json.Marshal(work)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledBytes)
|
||||
}
|
||||
|
||||
// InjectDecoder implements admission.DecoderInjector interface.
|
||||
// A decoder will be automatically injected.
|
||||
func (a *MutatingAdmission) InjectDecoder(d *admission.Decoder) error {
|
||||
a.decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveIrrelevantField will delete irrelevant field from workload. such as uid, timestamp, status
|
||||
func removeIrrelevantField(workload *unstructured.Unstructured) {
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "creationTimestamp")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "generation")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "resourceVersion")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "selfLink")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "managedFields")
|
||||
unstructured.RemoveNestedField(workload.Object, "metadata", "uid")
|
||||
unstructured.RemoveNestedField(workload.Object, "status")
|
||||
unstructured.RemoveNestedField(workload.Object, "spec", "clusterIP")
|
||||
}
|
||||
Loading…
Reference in New Issue