diff --git a/CHANGELOG.md b/CHANGELOG.md index 7792b95d4..d966e6d91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - (Bugfix) (Platform) Cover NoAuth Case for Identity Service - (Feature) Add ArangoMember Args - (Maintenance) Unify References via golangci-linter +- (Feature) Add Default Container Mods ## [1.2.47](https://github.com/arangodb/kube-arangodb/tree/1.2.47) (2025-03-28) - (Bugfix) Use Profile Annotations diff --git a/Makefile b/Makefile index ad97165c8..2f172d7ee 100644 --- a/Makefile +++ b/Makefile @@ -794,7 +794,7 @@ init: vendor tools update-generated $(BIN) .PHONY: tools-min tools-min: update-vendor @echo ">> Fetching golangci-lint linter" - @GOBIN=$(GOPATH)/bin go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.63.4 + @GOBIN=$(GOPATH)/bin go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 @echo ">> Fetching goimports" @GOBIN=$(GOPATH)/bin go install golang.org/x/tools/cmd/goimports@v0.19.0 @echo ">> Fetching license check" diff --git a/docs/api/ArangoProfile.V1Beta1.md b/docs/api/ArangoProfile.V1Beta1.md index 83f671de0..d955b3756 100644 --- a/docs/api/ArangoProfile.V1Beta1.md +++ b/docs/api/ArangoProfile.V1Beta1.md @@ -230,6 +230,190 @@ might be configured in the container image. *** +### .spec.template.container.default.args + +Type: `array` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/core.go#L54) + +Arguments to the entrypoint. +The container image's CMD is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. + +Links: +* [Kubernetes Docs](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell) + +*** + +### .spec.template.container.default.command + +Type: `array` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/core.go#L44) + +Entrypoint array. Not executed within a shell. +The container image's ENTRYPOINT is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. + +Links: +* [Kubernetes Docs](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell) + +*** + +### .spec.template.container.default.env + +Type: `core.EnvVar` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/environments.go#L36) + +Env keeps the information about environment variables provided to the container + +Links: +* [Kubernetes Docs](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#envvar-v1-core) + +*** + +### .spec.template.container.default.envFrom + +Type: `core.EnvFromSource` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/environments.go#L41) + +EnvFrom keeps the information about environment variable sources provided to the container + +Links: +* [Kubernetes Docs](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#envfromsource-v1-core) + +*** + +### .spec.template.container.default.image + +Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/image.go#L35) + +Image define image details + +*** + +### .spec.template.container.default.imagePullPolicy + +Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/image.go#L39) + +ImagePullPolicy define Image pull policy + +Default Value: `IfNotPresent` + +*** + +### .spec.template.container.default.lifecycle + +Type: `core.Lifecycle` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/lifecycle.go#L35) + +Lifecycle keeps actions that the management system should take in response to container lifecycle events. + +*** + +### .spec.template.container.default.livenessProbe + +Type: `core.Probe` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L37) + +LivenessProbe keeps configuration of periodic probe of container liveness. +Container will be restarted if the probe fails. + +Links: +* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes) + +*** + +### .spec.template.container.default.method + +Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/policy/merge.go#L32) + +Method defines the merge method + +Possible Values: +* `"override"` (default) - Overrides values during configuration merge +* `"append"` - Appends, if possible, values during configuration merge + +*** + +### .spec.template.container.default.ports + +Type: `[]core.ContainerPort` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/networking.go#L39) + +Ports contains list of ports to expose from the container. Not specifying a port here +DOES NOT prevent that port from being exposed. Any port which is +listening on the default "0.0.0.0" address inside a container will be +accessible from the network. + +*** + +### .spec.template.container.default.readinessProbe + +Type: `core.Probe` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L42) + +ReadinessProbe keeps configuration of periodic probe of container service readiness. +Container will be removed from service endpoints if the probe fails. + +Links: +* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes) + +*** + +### .spec.template.container.default.resources + +Type: `core.ResourceRequirements` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/resources.go#L37) + +Resources holds resource requests & limits for container + +Links: +* [Documentation of core.ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#resourcerequirements-v1-core) + +*** + +### .spec.template.container.default.securityContext + +Type: `core.SecurityContext` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/security.go#L35) + +SecurityContext holds container-level security attributes and common container settings. + +Links: +* [Kubernetes docs](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) + +*** + +### .spec.template.container.default.startupProbe + +Type: `core.Probe` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/probes.go#L50) + +StartupProbe indicates that the Pod has successfully initialized. +If specified, no other probes are executed until this completes successfully. +If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. +This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, +when it might take a long time to load data or warm a cache, than during steady-state operation. + +Links: +* [Kubernetes docs](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes) + +*** + +### .spec.template.container.default.volumeMounts + +Type: `[]core.VolumeMount` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/volume_mounts.go#L35) + +VolumeMounts keeps list of pod volumes to mount into the container's filesystem. + +*** + +### .spec.template.container.default.workingDir + +Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/container/resources/core.go#L59) + +Container's working directory. +If not specified, the container runtime's default will be used, which +might be configured in the container image. + +*** + ### .spec.template.pod.affinity Type: `core.Affinity` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/scheduler/v1beta1/pod/resources/scheduling.go#L44) diff --git a/pkg/apis/scheduler/v1beta1/profile_container_template.go b/pkg/apis/scheduler/v1beta1/profile_container_template.go index 9c5f27233..52625e0f3 100644 --- a/pkg/apis/scheduler/v1beta1/profile_container_template.go +++ b/pkg/apis/scheduler/v1beta1/profile_container_template.go @@ -1,7 +1,7 @@ // // DISCLAIMER // -// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import ( schedulerContainerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1/container" shared "github.com/arangodb/kube-arangodb/pkg/apis/shared" + "github.com/arangodb/kube-arangodb/pkg/util/errors" ) type ProfileContainerTemplate struct { @@ -33,6 +34,9 @@ type ProfileContainerTemplate struct { // All applies generic values to all Containers All *schedulerContainerApi.Generic `json:"all,omitempty"` + + // Default applies generic values to default Container (first one on the list) + Default *schedulerContainerApi.Container `json:"default,omitempty"` } func (p *ProfileContainerTemplate) ApplyContainers(template *core.PodTemplateSpec) error { @@ -51,6 +55,32 @@ func (p *ProfileContainerTemplate) ApplyGeneric(template *core.PodTemplateSpec) return p.All.Apply(template) } +func (p *ProfileContainerTemplate) ApplyDefault(template *core.PodTemplateSpec) error { + if p == nil { + return nil + } + + if template == nil { + return errors.Errorf("Template is nil") + } + + if len(template.Spec.Containers) == 0 { + return errors.Errorf("Default container is missing") + } + + var cont core.Container + + template.Spec.Containers[0].DeepCopyInto(&cont) + + if err := p.Default.Apply(template, &cont); err != nil { + return err + } + + template.Spec.Containers[0] = cont + + return nil +} + func (p *ProfileContainerTemplate) With(other *ProfileContainerTemplate) *ProfileContainerTemplate { if p == nil && other == nil { return nil @@ -67,6 +97,7 @@ func (p *ProfileContainerTemplate) With(other *ProfileContainerTemplate) *Profil return &ProfileContainerTemplate{ Containers: p.Containers.With(other.Containers), All: p.All.With(other.All), + Default: p.Default.With(other.Default), } } diff --git a/pkg/apis/scheduler/v1beta1/profile_templates.go b/pkg/apis/scheduler/v1beta1/profile_templates.go index 4e6e45e5f..6faa968a0 100644 --- a/pkg/apis/scheduler/v1beta1/profile_templates.go +++ b/pkg/apis/scheduler/v1beta1/profile_templates.go @@ -1,7 +1,7 @@ // // DISCLAIMER // -// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -65,6 +65,11 @@ func (p ProfileTemplates) RenderOnTemplate(pod *core.PodTemplateSpec) error { return errors.Wrapf(err, "Error while rendering ArangoSchedulerPod") } + // Apply Default Containers Spec + if err := t.GetContainer().ApplyDefault(pod); err != nil { + return errors.Wrapf(err, "Error while rendering ArangoSchedulerPod") + } + // Apply Containers Spec if err := t.GetContainer().ApplyContainers(pod); err != nil { return errors.Wrapf(err, "Error while rendering ArangoSchedulerPod") diff --git a/pkg/apis/scheduler/v1beta1/zz_generated.deepcopy.go b/pkg/apis/scheduler/v1beta1/zz_generated.deepcopy.go index 4339c3a37..6aafcda18 100644 --- a/pkg/apis/scheduler/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/scheduler/v1beta1/zz_generated.deepcopy.go @@ -561,6 +561,11 @@ func (in *ProfileContainerTemplate) DeepCopyInto(out *ProfileContainerTemplate) *out = new(container.Generic) (*in).DeepCopyInto(*out) } + if in.Default != nil { + in, out := &in.Default, &out.Default + *out = new(container.Container) + (*in).DeepCopyInto(*out) + } return } diff --git a/pkg/crd/crds/scheduler-profile.schema.generated.yaml b/pkg/crd/crds/scheduler-profile.schema.generated.yaml index aaa0b7cff..302d6410d 100644 --- a/pkg/crd/crds/scheduler-profile.schema.generated.yaml +++ b/pkg/crd/crds/scheduler-profile.schema.generated.yaml @@ -2419,6 +2419,506 @@ v1beta1: type: object description: Containers applies values per container type: object + default: + description: Default applies generic values to default Container (first one on the list) + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + type: string + x-kubernetes-int-or-string: true + resource: + type: string + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + type: object + type: object + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + type: string + port: + type: string + x-kubernetes-int-or-string: true + scheme: + type: string + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + type: object + tcpSocket: + properties: + host: + type: string + port: + type: string + x-kubernetes-int-or-string: true + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + type: string + port: + type: string + x-kubernetes-int-or-string: true + scheme: + type: string + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + type: object + tcpSocket: + properties: + host: + type: string + port: + type: string + x-kubernetes-int-or-string: true + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + type: string + port: + type: string + x-kubernetes-int-or-string: true + scheme: + type: string + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + type: string + x-kubernetes-int-or-string: true + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + method: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + type: string + type: object + type: array + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + type: string + port: + type: string + x-kubernetes-int-or-string: true + scheme: + type: string + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + type: string + x-kubernetes-int-or-string: true + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + type: object + type: array + limits: + additionalProperties: + type: string + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + type: string + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + type: object + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + path: + type: string + port: + type: string + x-kubernetes-int-or-string: true + scheme: + type: string + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + type: string + x-kubernetes-int-or-string: true + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + type: object + type: array + workingDir: + type: string + type: object type: object pod: description: Pod Template diff --git a/pkg/handlers/scheduler/webhooks/policies/handler.go b/pkg/handlers/scheduler/webhooks/policies/handler.go index 6de77a7dc..f739fd73f 100644 --- a/pkg/handlers/scheduler/webhooks/policies/handler.go +++ b/pkg/handlers/scheduler/webhooks/policies/handler.go @@ -65,8 +65,15 @@ func (h handler) CanHandle(ctx context.Context, log logging.Logger, t webhook.Ad return false } - _, ok := new.GetLabels()[constants.ProfilesDeployment] - return ok + if _, ok := new.GetLabels()[constants.ProfilesDeployment]; ok { + return true + } + + if _, ok := new.GetLabels()[constants.ProfilesApplyLabel]; ok { + return true + } + + return false } func (h handler) Mutate(ctx context.Context, log logging.Logger, t webhook.AdmissionRequestType, request *admission.AdmissionRequest, old, new *core.Pod) (webhook.MutationResponse, error) { @@ -77,17 +84,17 @@ func (h handler) Mutate(ctx context.Context, log logging.Logger, t webhook.Admis labels := new.GetLabels() annotations := new.GetAnnotations() - v := labels[constants.ProfilesDeployment] - depl, err := h.client.Arango().DatabaseV1().ArangoDeployments(request.Namespace).Get(ctx, v, meta.GetOptions{}) - if err != nil { - if kerrors.IsNotFound(err) { + if v, ok := labels[constants.ProfilesDeployment]; ok { + if _, err := h.client.Arango().DatabaseV1().ArangoDeployments(request.Namespace).Get(ctx, v, meta.GetOptions{}); err != nil { + if kerrors.IsNotFound(err) { + return webhook.MutationResponse{ + ValidationResponse: webhook.NewValidationResponse(false, "ArangoDeployment %s/%s not found", request.Namespace, v), + }, nil + } return webhook.MutationResponse{ - ValidationResponse: webhook.NewValidationResponse(false, "ArangoDeployment %s/%s not found", request.Namespace, v), + ValidationResponse: webhook.NewValidationResponse(false, "Unable to get ArangoDeployment %s/%s: %s", request.Namespace, v, err.Error()), }, nil } - return webhook.MutationResponse{ - ValidationResponse: webhook.NewValidationResponse(false, "Unable to get ArangoDeployment %s/%s: %s", request.Namespace, v, err.Error()), - }, nil } allProfiles := util.FlattenLists(goStrings.Split(labels[constants.ProfilesList], ","), goStrings.Split(annotations[constants.ProfilesList], ",")) @@ -97,7 +104,7 @@ func (h handler) Mutate(ctx context.Context, log logging.Logger, t webhook.Admis return s != "" }) - calculatedProfiles, profilesChecksum, err := scheduler.Profiles(ctx, h.client.Arango().SchedulerV1beta1().ArangoProfiles(depl.GetNamespace()), labels, profiles...) + calculatedProfiles, profilesChecksum, err := scheduler.Profiles(ctx, h.client.Arango().SchedulerV1beta1().ArangoProfiles(new.GetNamespace()), labels, profiles...) if err != nil { return webhook.MutationResponse{ ValidationResponse: webhook.NewValidationResponse(false, "Unable to get ArangoProfiles: %s", err.Error()), diff --git a/pkg/util/constants/profiles.go b/pkg/util/constants/profiles.go index 63b7bb185..aec6e3de7 100644 --- a/pkg/util/constants/profiles.go +++ b/pkg/util/constants/profiles.go @@ -1,7 +1,7 @@ // // DISCLAIMER // -// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ const ProfileGroup = "profiles.arangodb.com" const ProfilesDeployment = ProfileGroup + "/deployment" const ProfilesIntegrationPrefix = "integration." + ProfileGroup const ProfilesList = ProfileGroup + "/profiles" +const ProfilesApplyLabel = ProfileGroup + "/apply" const ProfilesAnnotationApplied = ProfileGroup + "/applied" const ProfilesAnnotationChecksum = ProfileGroup + "/checksum" diff --git a/pkg/webhook/admission.go b/pkg/webhook/admission.go index 0c6744922..906002ce4 100644 --- a/pkg/webhook/admission.go +++ b/pkg/webhook/admission.go @@ -151,6 +151,7 @@ func (a admissionImpl[T]) request(t AdmissionRequestType, writer goHttp.Response code, data := a.requestWriterJSON(ctx, log, t, request) writer.WriteHeader(code) + log.Int("code", code).Str("data", string(data)).Info("Request Response send") if len(data) > 0 { if _, err := util.WriteAll(writer, data); err != nil { log.Err(err).Warn("Unable to send response")