From fc5f5802434c194205782729b36ef5e0e43c0faf Mon Sep 17 00:00:00 2001 From: Andy Kolibri Vendetti Date: Wed, 30 Apr 2025 01:04:13 +0500 Subject: [PATCH] comments fixes --- .../nodetainterconfig_controller.go | 80 ++++++------------- 1 file changed, 26 insertions(+), 54 deletions(-) diff --git a/internal/controller/nodetainterconfig_controller.go b/internal/controller/nodetainterconfig_controller.go index ed97159..1146f87 100644 --- a/internal/controller/nodetainterconfig_controller.go +++ b/internal/controller/nodetainterconfig_controller.go @@ -221,23 +221,23 @@ func (r *NodeTainterConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { // --- UTILS FUNCTIONS --- -// TaintToString конвертирует тейнт в строку для статуса/логов +// Converts Taint to string for status/logs func TaintToString(taint *corev1.Taint) string { return fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect) } -// TaintsToString конвертирует слайс тейнтов в слайс строк +// Converts Taints slice to string slice func TaintsToStrings(taints []corev1.Taint) []string { res := make([]string, len(taints)) for i, t := range taints { res[i] = TaintToString(&t) } - sort.Strings(res) // Сортируем для консистентности статуса + sort.Strings(res) return res } -// parseLabelRulesFromSpec парсит правила из CRD Spec -// Возвращает map["labelKey=labelValue"]corev1.Taint и ошибки +// Parses rules from CRD Spec +// returns map["labelKey=labelValue"]corev1.Taint and errors func parseLabelRulesFromSpec(specLabelRules map[string]string) (map[string]corev1.Taint, []error) { parsed := make(map[string]corev1.Taint) var errs []error @@ -251,25 +251,24 @@ func parseLabelRulesFromSpec(specLabelRules map[string]string) (map[string]corev continue } - // Парсим селектор "key=value" partsSelector := strings.SplitN(ruleSelector, "=", 2) - if len(partsSelector) != 2 { // Должен быть знак = + if len(partsSelector) != 2 { errs = append(errs, fmt.Errorf("invalid rule selector format '%s': missing '='", ruleSelector)) continue } labelKey := strings.TrimSpace(partsSelector[0]) - labelValue := strings.TrimSpace(partsSelector[1]) // Может быть пустым! + labelValue := strings.TrimSpace(partsSelector[1]) if labelKey == "" { errs = append(errs, fmt.Errorf("invalid rule selector format '%s': empty label key", ruleSelector)) continue } - // Валидируем ключ лейбла + if msgs := apivalidation.IsQualifiedName(labelKey); len(msgs) > 0 { errs = append(errs, fmt.Errorf("invalid label key in selector '%s': %v", ruleSelector, msgs)) continue } - // Валидируем значение лейбла (если не пустое) + if labelValue != "" { if msgs := apivalidation.IsValidLabelValue(labelValue); len(msgs) > 0 { errs = append(errs, fmt.Errorf("invalid label value in selector '%s': %v", ruleSelector, msgs)) @@ -277,7 +276,6 @@ func parseLabelRulesFromSpec(specLabelRules map[string]string) (map[string]corev } } - // Парсим строку тейнта "key=value:Effect" (используем улучшенную логику из прошлого ответа) partsEffect := strings.SplitN(taintString, ":", 2) if len(partsEffect) != 2 || partsEffect[1] == "" { errs = append(errs, fmt.Errorf("invalid taint format for rule '%s': '%s' (missing effect)", ruleSelector, taintString)) @@ -311,35 +309,31 @@ func parseLabelRulesFromSpec(specLabelRules map[string]string) (map[string]corev continue } - // Все ок taint := corev1.Taint{Key: taintKey, Value: taintValue, Effect: effect} - parsed[ruleSelector] = taint // Ключ = "labelKey=labelValue" + parsed[ruleSelector] = taint // Key = "labelKey=labelValue" } return parsed, errs } -// calculateDesiredTaints определяет тейнты на основе лейблов ноды и правил +// Defines Taints depending on node labels and rules func calculateDesiredTaints(nodeLabels map[string]string, parsedLabelRules map[string]corev1.Taint) []corev1.Taint { desired := []corev1.Taint{} - foundTaints := make(map[string]bool) // Для уникальности Key:Effect + foundTaints := make(map[string]bool) if nodeLabels == nil { - nodeLabels = make(map[string]string) // Безопасность + nodeLabels = make(map[string]string) } for ruleSelector, taint := range parsedLabelRules { parts := strings.SplitN(ruleSelector, "=", 2) if len(parts) != 2 { continue - } // Уже должно быть отва лидировано + } ruleKey := parts[0] - ruleValue := parts[1] // Может быть пустой + ruleValue := parts[1] actualValue, exists := nodeLabels[ruleKey] - // Логика сравнения: - // 1. Ключ лейбла должен существовать на ноде. - // 2. Значение лейбла на ноде должно ТОЧНО совпадать со значением в правиле (включая пустую строку). if exists && actualValue == ruleValue { taintKeyEffect := fmt.Sprintf("%s:%s", taint.Key, taint.Effect) if !foundTaints[taintKeyEffect] { @@ -351,22 +345,19 @@ func calculateDesiredTaints(nodeLabels map[string]string, parsedLabelRules map[s return desired } -// TaintKeyEffect создает уникальную строку для тейнта (Key:Effect) +// Creates unique string for Taint (Key:Effect) func TaintKeyEffect(taint *corev1.Taint) string { return fmt.Sprintf("%s:%s", taint.Key, taint.Effect) } -// mergeAndCheckTaints сравнивает текущие и желаемые тейнты, управляемые оператором. -// parsedLabelRules: map["labelKey=labelValue"]corev1.Taint - содержит ВСЕ валидные правила из конфига. +// Compares current and desired controlled Taints func mergeAndCheckTaints(currentTaints []corev1.Taint, desiredTaints []corev1.Taint, parsedLabelRules map[string]corev1.Taint) (bool, []corev1.Taint) { - // 1. Определяем, какие типы тейнтов (Key:Effect) управляются нами по всем правилам managedTaintTypes := sets.NewString() - for _, ruleTaint := range parsedLabelRules { // Итерируем по значениям (Taint объектам) + for _, ruleTaint := range parsedLabelRules { managedTaintTypes.Insert(TaintKeyEffect(&ruleTaint)) } - // 2. Разделяем текущие тейнты на управляемые и неуправляемые - currentManagedTaints := make(map[string]corev1.Taint) // key:Effect -> Taint + currentManagedTaints := make(map[string]corev1.Taint) unmanagedTaints := []corev1.Taint{} for _, taint := range currentTaints { ke := TaintKeyEffect(&taint) @@ -377,31 +368,27 @@ func mergeAndCheckTaints(currentTaints []corev1.Taint, desiredTaints []corev1.Ta } } - // 3. Создаем map желаемых тейнтов для быстрого поиска desiredTaintsMap := make(map[string]corev1.Taint) // key:Effect -> Taint for _, taint := range desiredTaints { - // Проверка, что желаемый тейнт действительно определен в правилах (на всякий случай) ke := TaintKeyEffect(&taint) if managedTaintTypes.Has(ke) { desiredTaintsMap[ke] = taint } } - // 4. Сравниваем управляемые текущие и желаемые needsUpdate := false if len(currentManagedTaints) != len(desiredTaintsMap) { needsUpdate = true } else { for ke, desiredTaint := range desiredTaintsMap { currentTaint, exists := currentManagedTaints[ke] - if !exists || currentTaint.Value != desiredTaint.Value { // Сравниваем и значения + if !exists || currentTaint.Value != desiredTaint.Value { needsUpdate = true break } } } - // 5. Собираем новый список тейнтов, если нужно обновление if needsUpdate { newTaints := make([]corev1.Taint, 0, len(unmanagedTaints)+len(desiredTaintsMap)) newTaints = append(newTaints, unmanagedTaints...) @@ -409,7 +396,7 @@ func mergeAndCheckTaints(currentTaints []corev1.Taint, desiredTaints []corev1.Ta for ke := range desiredTaintsMap { desiredKeys = append(desiredKeys, ke) } - sort.Strings(desiredKeys) // Сортируем для консистентности + sort.Strings(desiredKeys) for _, ke := range desiredKeys { newTaints = append(newTaints, desiredTaintsMap[ke]) } @@ -419,16 +406,14 @@ func mergeAndCheckTaints(currentTaints []corev1.Taint, desiredTaints []corev1.Ta return false, currentTaints } -// updateCRDStatus обновляет статус ресурса NodeTainterConfig -// TODO: Вызывать эту функцию при изменении CRD или при старте/ошибках контроллера. +// Updates NodeTainterConfig status +// TODO: Call this function on CRD updates or controller start/errors func (r *NodeTainterConfigReconciler) updateCRDStatus(ctx context.Context, config *configv1alpha1.NodeTainterConfig, status metav1.ConditionStatus, reason, message string) error { log := log.FromContext(ctx).WithValues("config", config.Name) configCopy := config.DeepCopy() - // Устанавливаем observedGeneration configCopy.Status.ObservedGeneration = config.Generation - // Обновляем Condition newCondition := metav1.Condition{ Type: ConditionTypeReady, Status: status, @@ -436,16 +421,12 @@ func (r *NodeTainterConfigReconciler) updateCRDStatus(ctx context.Context, confi Message: message, LastTransitionTime: metav1.Now(), } - // TODO: Использовать 'meta.SetStatusCondition' из 'k8s.io/apimachinery/pkg/api/meta' для правильного обновления conditions - // Примерно так: - // meta.SetStatusCondition(&configCopy.Status.Conditions, newCondition) - // Пока просто заменяем для простоты + // TODO: Use 'meta.SetStatusCondition' from 'k8s.io/apimachinery/pkg/api/meta' for correct conditions updates configCopy.Status.Conditions = []metav1.Condition{newCondition} - // TODO: Обновить NodeTaintStatus на основе данных со всех нод (может быть сложно и затратно) + // TODO: Update NodeTaintStatus based on data from all nodes // configCopy.Status.NodeTaintStatus = ... - // Используем Patch для обновления статуса if err := r.Status().Patch(ctx, configCopy, client.MergeFrom(config)); err != nil { log.Error(err, "Failed to patch NodeTainterConfig status") return err @@ -454,26 +435,19 @@ func (r *NodeTainterConfigReconciler) updateCRDStatus(ctx context.Context, confi return nil } -// updateNodeTaintStatus обновляет информацию о тейнтах для конкретной ноды в статусе CRD -// TODO: Эта функция в текущем виде будет вызывать конфликты, т.к. каждый Reconcile ноды -// будет пытаться перезаписать весь Status.NodeTaintStatus. -// Правильный подход: читать текущий статус CRD, обновлять только запись для текущей ноды, патчить. -// Это усложняет код, пока оставим так для демонстрации, но ЭТО НУЖНО ИСПРАВИТЬ для production. +// Updates info about Taints for correct Node in CRD status func (r *NodeTainterConfigReconciler) updateNodeTaintStatus(ctx context.Context, node *corev1.Node, appliedTaints []corev1.Taint, errorMsg string) error { log := log.FromContext(ctx).WithValues("node", node.Name) var config configv1alpha1.NodeTainterConfig configKey := types.NamespacedName{Name: GlobalTaintConfigName} - // Получаем CRD еще раз, чтобы обновить его статус if err := r.Get(ctx, configKey, &config); err != nil { log.Error(err, "Failed to get NodeTainterConfig for status update", "configName", GlobalTaintConfigName) - // Не можем обновить статус, если не получили CRD return fmt.Errorf("failed to get config %s for status update: %w", GlobalTaintConfigName, err) } configCopy := config.DeepCopy() - // Ищем статус для текущей ноды found := false nodeStatus := configv1alpha1.NodeTaintInfo{ NodeName: node.Name, @@ -492,12 +466,10 @@ func (r *NodeTainterConfigReconciler) updateNodeTaintStatus(ctx context.Context, configCopy.Status.NodeTaintStatus = append(configCopy.Status.NodeTaintStatus, nodeStatus) } - // Сортируем для консистентности sort.Slice(configCopy.Status.NodeTaintStatus, func(i, j int) bool { return configCopy.Status.NodeTaintStatus[i].NodeName < configCopy.Status.NodeTaintStatus[j].NodeName }) - // Патчим статус if err := r.Status().Patch(ctx, configCopy, client.MergeFrom(&config)); err != nil { log.Error(err, "Failed to patch NodeTainterConfig status with node info", "node", node.Name) return err