diff --git a/api/v1alphav1/overcommitclass_types.go b/api/v1alphav1/overcommitclass_types.go index 60beab0..62724e9 100644 --- a/api/v1alphav1/overcommitclass_types.go +++ b/api/v1alphav1/overcommitclass_types.go @@ -8,7 +8,6 @@ package v1alphav1 import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! @@ -68,146 +67,6 @@ type OvercommitClass struct { Status OvercommitClassStatus `json:"status,omitempty"` } -// GetAnnotations implements v1.Object. -func (in *OvercommitClass) GetAnnotations() map[string]string { - return in.ObjectMeta.Annotations -} - -// GetCreationTimestamp implements v1.Object. -func (in *OvercommitClass) GetCreationTimestamp() metav1.Time { - return in.ObjectMeta.CreationTimestamp -} - -// GetDeletionGracePeriodSeconds implements v1.Object. -func (in *OvercommitClass) GetDeletionGracePeriodSeconds() *int64 { - return in.ObjectMeta.DeletionGracePeriodSeconds -} - -// GetDeletionTimestamp implements v1.Object. -func (in *OvercommitClass) GetDeletionTimestamp() *metav1.Time { - return in.ObjectMeta.DeletionTimestamp -} - -// GetFinalizers implements v1.Object. -func (in *OvercommitClass) GetFinalizers() []string { - return in.ObjectMeta.Finalizers -} - -// GetGenerateName implements v1.Object. -func (in *OvercommitClass) GetGenerateName() string { - return in.ObjectMeta.GenerateName -} - -// GetGeneration implements v1.Object. -func (in *OvercommitClass) GetGeneration() int64 { - return in.ObjectMeta.Generation -} - -// GetLabels implements v1.Object. -func (in *OvercommitClass) GetLabels() map[string]string { - return in.ObjectMeta.Labels -} - -// GetManagedFields implements v1.Object. -func (in *OvercommitClass) GetManagedFields() []metav1.ManagedFieldsEntry { - return in.ObjectMeta.ManagedFields -} - -// GetName implements v1.Object. -func (in *OvercommitClass) GetName() string { - return in.ObjectMeta.Name -} - -// GetNamespace implements v1.Object. -func (in *OvercommitClass) GetNamespace() string { - return in.ObjectMeta.Namespace -} - -// GetOwnerReferences implements v1.Object. -func (in *OvercommitClass) GetOwnerReferences() []metav1.OwnerReference { - return in.ObjectMeta.OwnerReferences -} - -// GetResourceVersion implements v1.Object. -func (in *OvercommitClass) GetResourceVersion() string { - return in.ObjectMeta.ResourceVersion -} - -// GetUID implements v1.Object. -func (in *OvercommitClass) GetUID() types.UID { - return in.ObjectMeta.UID -} - -// SetAnnotations implements v1.Object. -func (in *OvercommitClass) SetAnnotations(annotations map[string]string) { - in.ObjectMeta.Annotations = annotations -} - -// SetCreationTimestamp implements v1.Object. -func (in *OvercommitClass) SetCreationTimestamp(timestamp metav1.Time) { - in.ObjectMeta.CreationTimestamp = timestamp -} - -// SetDeletionGracePeriodSeconds implements v1.Object. -func (in *OvercommitClass) SetDeletionGracePeriodSeconds(seconds *int64) { - in.ObjectMeta.DeletionGracePeriodSeconds = seconds -} - -// SetDeletionTimestamp implements v1.Object. -func (in *OvercommitClass) SetDeletionTimestamp(timestamp *metav1.Time) { - in.ObjectMeta.DeletionTimestamp = timestamp -} - -// SetFinalizers implements v1.Object. -func (in *OvercommitClass) SetFinalizers(finalizers []string) { - in.ObjectMeta.Finalizers = finalizers -} - -// SetGenerateName implements v1.Object. -func (in *OvercommitClass) SetGenerateName(name string) { - in.ObjectMeta.GenerateName = name -} - -// SetGeneration implements v1.Object. -func (in *OvercommitClass) SetGeneration(generation int64) { - in.ObjectMeta.Generation = generation -} - -// SetLabels implements v1.Object. -func (in *OvercommitClass) SetLabels(labels map[string]string) { - in.ObjectMeta.Labels = labels -} - -// SetManagedFields implements v1.Object. -func (in *OvercommitClass) SetManagedFields(managedFields []metav1.ManagedFieldsEntry) { - in.ObjectMeta.ManagedFields = managedFields -} - -// SetName implements v1.Object. -func (in *OvercommitClass) SetName(name string) { - in.ObjectMeta.Name = name -} - -// SetNamespace implements v1.Object. -func (in *OvercommitClass) SetNamespace(namespace string) { - in.ObjectMeta.Namespace = namespace -} - -// SetOwnerReferences implements v1.Object. -func (in *OvercommitClass) SetOwnerReferences(references []metav1.OwnerReference) { - in.ObjectMeta.OwnerReferences = references -} - -// SetResourceVersion implements v1.Object. -func (in *OvercommitClass) SetResourceVersion(version string) { - in.ObjectMeta.ResourceVersion = version -} - -// SetUID implements v1.Object. -func (in *OvercommitClass) SetUID(uid types.UID) { - in.ObjectMeta.UID = uid -} - // +kubebuilder:object:root=true // OvercommitClassList contains a list of OvercommitClass diff --git a/api/v1alphav1/webhook_validations.go b/api/v1alphav1/webhook_validations.go index 06b114d..cdd173d 100644 --- a/api/v1alphav1/webhook_validations.go +++ b/api/v1alphav1/webhook_validations.go @@ -70,9 +70,14 @@ func isClassDefault(class OvercommitClass, client client.Client) error { } func checkIsRegexValid(regex string) error { + // Limit regex length to prevent ReDoS (catastrophic backtracking) + const maxRegexLen = 512 + if len(regex) > maxRegexLen { + return fmt.Errorf("regex is too long (%d chars), maximum allowed is %d", len(regex), maxRegexLen) + } _, err := regexp.Compile(regex) if err != nil { - return errors.New("Error: the regex is not valid") + return fmt.Errorf("invalid regex for excludedNamespaces: %w", err) } return nil } diff --git a/cmd/main.go b/cmd/main.go index d53b89d..cad43e6 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -150,7 +150,7 @@ func main() { os.Exit(1) } - serviceAccountName, err := utils.GetPodServiceAccount(mgr.GetAPIReader()) + serviceAccountName, err := utils.GetPodServiceAccount(ctx, mgr.GetAPIReader()) if err != nil { setupLog.Error(err, "unable to get pod service account") os.Exit(1) diff --git a/go.mod b/go.mod index a07a135..82aa6fc 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( k8s.io/apimachinery v0.32.1 k8s.io/client-go v0.32.1 sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/yaml v1.4.0 ) require ( @@ -101,4 +100,5 @@ require ( sigs.k8s.io/gateway-api v1.1.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/internal/controller/overcommit/overcommit_controller.go b/internal/controller/overcommit/overcommit_controller.go index 59a15b7..85a5351 100644 --- a/internal/controller/overcommit/overcommit_controller.go +++ b/internal/controller/overcommit/overcommit_controller.go @@ -390,11 +390,8 @@ func (r *OvercommitReconciler) Reconcile(ctx context.Context, req ctrl.Request) // Don't fail the reconciliation for status update errors } - // Only requeue periodically for status checks, not immediately - logger.Info("Reconciliation completed successfully", "nextReconcile", "10 seconds", "time", time.Now().Format("15:04:05")) - return ctrl.Result{ - RequeueAfter: time.Second * 10, - }, nil + logger.Info("Reconciliation completed successfully", "time", time.Now().Format("15:04:05")) + return ctrl.Result{}, nil } // +kubebuilder:rbac:groups=apps, resources=deployments;replicasets,verbs=get;list;watch;create;update;patch;delete diff --git a/internal/controller/overcommitclass/overcommitclass_controller.go b/internal/controller/overcommitclass/overcommitclass_controller.go index 9d1532e..e09dc5c 100644 --- a/internal/controller/overcommitclass/overcommitclass_controller.go +++ b/internal/controller/overcommitclass/overcommitclass_controller.go @@ -393,9 +393,6 @@ func (r *OvercommitClassReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } - // Only requeue periodically for status checks, not immediately - logger.Info("Reconciliation completed successfully", "nextReconcile", "10 seconds", "time", time.Now().Format("15:04:05")) - return ctrl.Result{ - RequeueAfter: 10 * time.Second, - }, nil + logger.Info("Reconciliation completed successfully", "time", time.Now().Format("15:04:05")) + return ctrl.Result{}, nil } diff --git a/internal/resources/generate_resources_pod_mutating_webhooks.go b/internal/resources/generate_resources_pod_mutating_webhooks.go index 05f7a19..2ccb51c 100644 --- a/internal/resources/generate_resources_pod_mutating_webhooks.go +++ b/internal/resources/generate_resources_pod_mutating_webhooks.go @@ -147,10 +147,10 @@ func CreateCertificate(name string, svc corev1.Service) *certmanager.Certificate Spec: certmanager.CertificateSpec{ SecretName: name + "-webhook-secret", Duration: &metav1.Duration{ - Duration: 87600 * time.Hour, + Duration: 8760 * time.Hour, // 1 year }, RenewBefore: &metav1.Duration{ - Duration: 720 * time.Hour, + Duration: 720 * time.Hour, // 30 days }, DNSNames: []string{ svc.Name + "." + svc.Namespace + ".svc", diff --git a/internal/resources/generate_resources_pod_mutating_webhooks_test.go b/internal/resources/generate_resources_pod_mutating_webhooks_test.go index f01448a..4549d1c 100644 --- a/internal/resources/generate_resources_pod_mutating_webhooks_test.go +++ b/internal/resources/generate_resources_pod_mutating_webhooks_test.go @@ -123,7 +123,7 @@ func TestCreateCertificate(t *testing.T) { t.Errorf("Expected secret name 'test-class-webhook-secret', got '%s'", certificate.Spec.SecretName) } - expectedDuration := 87600 * time.Hour + expectedDuration := 8760 * time.Hour if certificate.Spec.Duration.Duration != expectedDuration { t.Errorf("Expected duration '%v', got '%v'", expectedDuration, certificate.Spec.Duration.Duration) } diff --git a/internal/utils/getOvercommitClass.go b/internal/utils/getOvercommitClass.go index 3323772..e4c7cf0 100644 --- a/internal/utils/getOvercommitClass.go +++ b/internal/utils/getOvercommitClass.go @@ -45,14 +45,14 @@ func GetOvercommitClassSpec(ctx context.Context, name string, k8sClient client.C return &overcommitClass.Spec, nil } -func GetDefaultSpec(k8sClient client.Client) (*overcommit.OvercommitClassSpec, error) { +func GetDefaultSpec(ctx context.Context, k8sClient client.Client) (*overcommit.OvercommitClassSpec, error) { if k8sClient == nil { return nil, errors.New("client parameter cannot be nil") } // List all OvercommitClass var overcommitClasses overcommit.OvercommitClassList - if err := k8sClient.List(context.Background(), &overcommitClasses); err != nil { + if err := k8sClient.List(ctx, &overcommitClasses); err != nil { return nil, fmt.Errorf("error listing OvercommitClass: %w", err) } diff --git a/internal/utils/getOvercommitClass_test.go b/internal/utils/getOvercommitClass_test.go index 6531fd1..1550636 100644 --- a/internal/utils/getOvercommitClass_test.go +++ b/internal/utils/getOvercommitClass_test.go @@ -82,7 +82,7 @@ var _ = Describe("GetDefaultSpec", func() { It("should retrieve the default OvercommitClassSpec correctly", func() { // Try the GetDefaultSpec function - spec, err := GetDefaultSpec(k8sClient) + spec, err := GetDefaultSpec(context.Background(), k8sClient) Expect(err).NotTo(HaveOccurred(), "Failed to get default OvercommitClassSpec") Expect(spec).NotTo(BeNil(), "Spec should not be nil") Expect(spec.IsDefault).To(BeTrue(), "Spec.IsDefault should be true") diff --git a/internal/utils/getPodDetails.go b/internal/utils/getPodDetails.go index 7899f55..1bbdcc0 100644 --- a/internal/utils/getPodDetails.go +++ b/internal/utils/getPodDetails.go @@ -58,7 +58,7 @@ func GetPodImageDetails(ctx context.Context, client client.Reader) (string, stri return "", "", "", fmt.Errorf("no containers found in pod") } -func GetPodServiceAccount(client client.Reader) (string, error) { +func GetPodServiceAccount(ctx context.Context, client client.Reader) (string, error) { podName := os.Getenv("POD_NAME") podNamespace := os.Getenv("POD_NAMESPACE") @@ -67,7 +67,7 @@ func GetPodServiceAccount(client client.Reader) (string, error) { } pod := &corev1.Pod{} - err := client.Get(context.TODO(), types.NamespacedName{ + err := client.Get(ctx, types.NamespacedName{ Name: podName, Namespace: podNamespace, }, pod) diff --git a/internal/webhook/v1alphav1/mutating/pod_webhook.go b/internal/webhook/v1alphav1/mutating/pod_webhook.go index 958d10b..54b946b 100644 --- a/internal/webhook/v1alphav1/mutating/pod_webhook.go +++ b/internal/webhook/v1alphav1/mutating/pod_webhook.go @@ -51,11 +51,11 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er } if isResize { - overcommit.OvercommitOnResize(pod, d.Recorder, d.Client) + overcommit.OvercommitOnResize(ctx, pod, d.Recorder, d.Client) return nil } - overcommit.Overcommit(pod, d.Recorder, d.Client) + overcommit.Overcommit(ctx, pod, d.Recorder, d.Client) return nil } diff --git a/pkg/overcommit/calculate_values_from_labels.go b/pkg/overcommit/calculate_values_from_labels.go index 3f1bdc9..8da1231 100644 --- a/pkg/overcommit/calculate_values_from_labels.go +++ b/pkg/overcommit/calculate_values_from_labels.go @@ -7,27 +7,24 @@ package overcommit import ( "context" - "fmt" "github.com/InditexTech/k8s-overcommit-operator/internal/metrics" "github.com/InditexTech/k8s-overcommit-operator/internal/utils" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" + k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) -// GetLabelValue gets the value of a label in the pod or in the namespace of the pod +// getNamespaceOvercommit gets the overcommit values from the namespace label or falls back to the default class. +// Returns (1.0, 1.0) as safe no-op values when any error occurs to avoid mutating pods incorrectly. func getNamespaceOvercommit(ctx context.Context, pod *corev1.Pod, client client.Client, label, ownerName, ownerKind string) (float64, float64) { // Get the namespace of the pod namespaceName := pod.ObjectMeta.Namespace var ns corev1.Namespace - namespace, err := getNamespaceYAML(ctx, namespaceName, client) + err := client.Get(ctx, k8sclient.ObjectKey{Name: namespaceName}, &ns) if err != nil { - podlog.Error(err, "Error getting the namespace yaml", "namespace", namespaceName) - } - err = yaml.Unmarshal([]byte(namespace), &ns) - if err != nil { - podlog.Error(err, "Error unmarshaling the namespace", "namespace", namespaceName) + podlog.Error(err, "Error getting the namespace", "namespace", namespaceName) + return 1.0, 1.0 } // Check if the overcommit class label is in the namespace @@ -36,53 +33,33 @@ func getNamespaceOvercommit(ctx context.Context, pod *corev1.Pod, client client. overcommitClass, err := utils.GetOvercommitClassSpec(ctx, val, client) if err != nil { podlog.Error(err, "Error getting the overcommit class", "overcommitClassLabel", val) + return 1.0, 1.0 } metrics.K8sOvercommitPodMutated.WithLabelValues(val, ownerKind, ownerName, pod.Namespace).Inc() return overcommitClass.CpuOvercommit, overcommitClass.MemoryOvercommit - } else { - podlog.Info("Overcommit class not found in the namespace, using the default", "namespace", ns.Name) - defaultClass, error := utils.GetDefaultSpec(client) - if error != nil { - podlog.Error(error, "Error getting the default overcommit class") - } - metrics.K8sOvercommitPodMutated.WithLabelValues("default", ownerKind, ownerName, pod.Namespace).Inc() - return defaultClass.CpuOvercommit, defaultClass.MemoryOvercommit - } -} - -// getNamespaceYAML gets the YAML of a namespace using the ServiceAccount token -func getNamespaceYAML(ctx context.Context, namespaceName string, k8sClient client.Client) (string, error) { - // Create a variable to store the Namespace object - var namespace corev1.Namespace - - // Get the Namespace object from the API server - err := k8sClient.Get(ctx, client.ObjectKey{ - Name: namespaceName, - }, &namespace) - if err != nil { - return "", fmt.Errorf("error getting the namespace: %v", err) } - // Convert the Namespace object to YAML - nsYAML, err := yaml.Marshal(namespace) + podlog.Info("Overcommit class not found in the namespace, using the default", "namespace", ns.Name) + defaultClass, err := utils.GetDefaultSpec(ctx, client) if err != nil { - return "", fmt.Errorf("error converting the namespace to YAML: %v", err) + podlog.Error(err, "Error getting the default overcommit class") + return 1.0, 1.0 } - - return string(nsYAML), nil + metrics.K8sOvercommitPodMutated.WithLabelValues("default", ownerKind, ownerName, pod.Namespace).Inc() + return defaultClass.CpuOvercommit, defaultClass.MemoryOvercommit } func checkOvercommitType(ctx context.Context, pod corev1.Pod, client client.Client) (float64, float64) { - var cpuValue float64 - var memoryValue float64 ownerName, ownerKind, err := utils.GetPodOwner(ctx, client, &pod) if err != nil { podlog.Error(err, "Error getting the pod owner") + // Non-fatal: continue with empty owner info } label, err := utils.GetOvercommitLabel(ctx, client) if err != nil { podlog.Error(err, "Error getting the overcommit label") + return 1.0, 1.0 } // Check if the pod has the overcommit class label value, exists := pod.Labels[label] @@ -96,17 +73,14 @@ func checkOvercommitType(ctx context.Context, pod corev1.Pod, client client.Clie overcommitClass, err := utils.GetOvercommitClassSpec(ctx, value, client) if err != nil { podlog.Error(err, "Error getting the overcommit class", "overcommitClassLabel", value) - // Overcommit class not found or some error - cpuValue, memoryValue = getNamespaceOvercommit(ctx, &pod, client, label, ownerName, ownerKind) - } else { - cpuValue, memoryValue = overcommitClass.CpuOvercommit, overcommitClass.MemoryOvercommit + // Overcommit class not found or some error, fall back to namespace/default + return getNamespaceOvercommit(ctx, &pod, client, label, ownerName, ownerKind) } metrics.K8sOvercommitPodMutated.WithLabelValues(value, ownerKind, ownerName, pod.Namespace).Inc() - } else { - // Overcommit class not found, checking the overcommit labels - podlog.Info("Overcommit class label not found in pod, checking the namespace") - cpuValue, memoryValue = getNamespaceOvercommit(ctx, &pod, client, label, ownerName, ownerKind) - + return overcommitClass.CpuOvercommit, overcommitClass.MemoryOvercommit } - return cpuValue, memoryValue + + // Overcommit class not found, checking the namespace + podlog.Info("Overcommit class label not found in pod, checking the namespace") + return getNamespaceOvercommit(ctx, &pod, client, label, ownerName, ownerKind) } diff --git a/pkg/overcommit/make_overcommit.go b/pkg/overcommit/make_overcommit.go index 2108024..4f99698 100644 --- a/pkg/overcommit/make_overcommit.go +++ b/pkg/overcommit/make_overcommit.go @@ -7,6 +7,7 @@ package overcommit import ( "context" + "fmt" "os" "github.com/InditexTech/k8s-overcommit-operator/internal/metrics" @@ -17,6 +18,11 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" ) +const ( + // AnnotationOvercommitApplied is set on pods after overcommit mutation to ensure idempotency. + AnnotationOvercommitApplied = "overcommit.inditex.dev/applied" +) + var podlog = logf.Log.WithName("overcommit") func mutateContainers(containers []corev1.Container, pod *corev1.Pod, cpuValue float64, memoryValue float64) { @@ -45,21 +51,32 @@ func mutateContainers(containers []corev1.Container, pod *corev1.Pod, cpuValue f } } -func Overcommit(pod *corev1.Pod, recorder record.EventRecorder, client client.Client) { - ctx := context.Background() +func Overcommit(ctx context.Context, pod *corev1.Pod, recorder record.EventRecorder, client client.Client) { + className := os.Getenv("OVERCOMMIT_CLASS_NAME") + + metrics.K8sOvercommitOperatorPodsRequestedTotal.WithLabelValues(className).Inc() - metrics.K8sOvercommitOperatorPodsRequestedTotal.WithLabelValues(os.Getenv("OVERCOMMIT_CLASS_NAME")).Inc() + // Idempotency: skip if this pod was already mutated by this class + if pod.Annotations != nil { + if applied, ok := pod.Annotations[AnnotationOvercommitApplied]; ok && applied == className { + podlog.Info("Pod already mutated by this overcommit class, skipping", "pod", pod.Name, "class", className) + return + } + } cpuValue, memoryValue := checkOvercommitType(ctx, *pod, client) mutateContainers(pod.Spec.Containers, pod, cpuValue, memoryValue) - // comportamiento actual para CREATE/UPDATE normales + // Also mutate init containers on regular CREATE/UPDATE if len(pod.Spec.InitContainers) > 0 { mutateContainers(pod.Spec.InitContainers, pod, cpuValue, memoryValue) } - metrics.K8sOvercommitOperatorMutatedPodsTotal.WithLabelValues(os.Getenv("OVERCOMMIT_CLASS_NAME")).Inc() + // Mark the pod as mutated to prevent double-application on reinvocation + setOvercommitAnnotation(pod, className, cpuValue, memoryValue) + + metrics.K8sOvercommitOperatorMutatedPodsTotal.WithLabelValues(className).Inc() recorder.Eventf( pod, @@ -67,23 +84,26 @@ func Overcommit(pod *corev1.Pod, recorder record.EventRecorder, client client.Cl "OvercommitApplied", "Applied overcommit to Pod '%s': OvercommitClass = %s, CPU Overcommit = %.2f, Memory Overcommit = %.2f", pod.Name, - os.Getenv("OVERCOMMIT_CLASS_NAME"), + className, cpuValue, memoryValue, ) } -func OvercommitOnResize(pod *corev1.Pod, recorder record.EventRecorder, client client.Client) { - ctx := context.Background() +func OvercommitOnResize(ctx context.Context, pod *corev1.Pod, recorder record.EventRecorder, client client.Client) { + className := os.Getenv("OVERCOMMIT_CLASS_NAME") - metrics.K8sOvercommitOperatorPodsRequestedTotal.WithLabelValues(os.Getenv("OVERCOMMIT_CLASS_NAME")).Inc() + metrics.K8sOvercommitOperatorPodsRequestedTotal.WithLabelValues(className).Inc() cpuValue, memoryValue := checkOvercommitType(ctx, *pod, client) - // En resize: solo containers normales. + // On resize: only mutate regular containers, skip init containers. mutateContainers(pod.Spec.Containers, pod, cpuValue, memoryValue) - metrics.K8sOvercommitOperatorMutatedPodsTotal.WithLabelValues(os.Getenv("OVERCOMMIT_CLASS_NAME")).Inc() + // Update annotation with new values after resize + setOvercommitAnnotation(pod, className, cpuValue, memoryValue) + + metrics.K8sOvercommitOperatorMutatedPodsTotal.WithLabelValues(className).Inc() recorder.Eventf( pod, @@ -91,8 +111,18 @@ func OvercommitOnResize(pod *corev1.Pod, recorder record.EventRecorder, client c "OvercommitAppliedOnResize", "Applied overcommit on resize to Pod '%s': OvercommitClass = %s, CPU Overcommit = %.2f, Memory Overcommit = %.2f", pod.Name, - os.Getenv("OVERCOMMIT_CLASS_NAME"), + className, cpuValue, memoryValue, ) } + +// setOvercommitAnnotation marks the pod as having been mutated by the overcommit webhook. +func setOvercommitAnnotation(pod *corev1.Pod, className string, cpuValue, memoryValue float64) { + if pod.Annotations == nil { + pod.Annotations = make(map[string]string) + } + pod.Annotations[AnnotationOvercommitApplied] = className + pod.Annotations["overcommit.inditex.dev/cpu"] = fmt.Sprintf("%.4f", cpuValue) + pod.Annotations["overcommit.inditex.dev/memory"] = fmt.Sprintf("%.4f", memoryValue) +} diff --git a/pkg/overcommit/make_overcommit_test.go b/pkg/overcommit/make_overcommit_test.go index 31e7866..a207fc8 100644 --- a/pkg/overcommit/make_overcommit_test.go +++ b/pkg/overcommit/make_overcommit_test.go @@ -6,6 +6,7 @@ package overcommit import ( + "context" "os" . "github.com/onsi/ginkgo/v2" @@ -91,7 +92,7 @@ var _ = Describe("Overcommit", func() { Describe("makeOvercommit", func() { It("should apply overcommit to containers", func() { - Overcommit(pod, recorder, k8sClient) + Overcommit(context.Background(), pod, recorder, k8sClient) Expect(pod.Spec.Containers[0].Resources.Requests).To(Equal(expectedRequests)) }) @@ -108,7 +109,7 @@ var _ = Describe("Overcommit", func() { }) It("should mutate pod containers and record an event", func() { - Overcommit(pod, recorder, k8sClient) + Overcommit(context.Background(), pod, recorder, k8sClient) Expect(pod.Spec.Containers[0].Resources.Requests).To(Equal(expectedRequests)) })