Как идиоматически заполнить пустые поля значениями по умолчанию для объектов Kubernetes API?

Я хочу сравнить два объекта API Kubernetes (например, v1.PodSpecs): один из них был создан вручную (ожидаемое состояние), другой был получен от API / клиента Kubernetes (фактическое состояние). Проблема в том, что даже если два объекта семантически равны, созданная вручную структура имеет нулевые значения для неопределенных полей, тогда как другая структура имеет значения по умолчанию, и поэтому два не совпадают. Это означает, что простого вызова reflect.DeepEqual() для сравнения недостаточно.

Например. после этого:

expected := &v1.Container{
    Name:  "busybox",
    Image: "busybox",
}

actual := getContainerSpecFromApi(...)

expected.ImagePullPolicy будет "", а actual.ImagePullPolicy будет "IfNotPresent" (значение по умолчанию), поэтому сравнение не выполняется.

Есть ли идиоматический способ конкретно заменить нулевые значения значениями по умолчанию в структурах Kubernetes API? Или, альтернативно, есть функция-конструктор, которая инициализирует структуру значениями по умолчанию, доступными для них где-то?

РЕДАКТИРОВАТЬ: В настоящее время я использую рукописные тесты на равенство для каждого типа объектов API K8s, но мне это не кажется поддерживаемым. Я ищу простую (набор) функцию (ы), которая «знает» значения по умолчанию для всех встроенных полей объекта Kubernetes API (возможно, где-то под k8s.io/api*?). Что-то вроде этого:

expected = api.ApplyContainerDefaults(expected)
if !reflect.DeepEqual(expected, actual) {
    reconcile(expected, actual)
}

person kispaljr    schedule 13.05.2019    source источник
comment
Я считаю, что идиоматический подход состоит в том, чтобы иметь внутри условие и присваивание для обработки истинного условия. То есть if field == "" { field = defaultvalue }.   -  person mkopriva    schedule 13.05.2019
comment
Вы, конечно, могли бы облегчить себе жизнь, используя reflect, чтобы сделать это за вас, но я не уверен, что это будет считаться идиоматическим. Тем не менее, если вам это нужно в основном для тестирования, я определенно рекомендую вам использовать reflect.   -  person mkopriva    schedule 13.05.2019
comment
Привет @mkopriva! Спасибо за ответ. Я понял, что мне недостаточно ясно, поэтому я отредактировал вопрос, чтобы отразить, что я не хочу вручную устанавливать все значения по умолчанию для всех возможных объектов API и для каждого поля, но хотел спросить, есть ли это уже реализовано в клиенте Go для меня?   -  person kispaljr    schedule 13.05.2019
comment
Если под клиентом вы имеете в виду Go std lib, то нет, ничего подобного готового нет. Если под клиентом вы имеете в виду пакеты, связанные с k8s, то, боюсь, я не знаю, я до сих пор не использовал кубернеты.   -  person mkopriva    schedule 13.05.2019
comment
Да, я имел в виду клиента Kubernetes. Еще раз извиняюсь за неряшливую формулировку   -  person kispaljr    schedule 13.05.2019
comment
@VasilyAngapov Я могу это сделать, но мне все равно придется вручную реализовать логику для всех проблемных полей всех объектов API, которые я использую, не так ли? Основная мотивация, стоящая за вопросом, - избежать этого.   -  person kispaljr    schedule 13.05.2019


Ответы (1)


Есть помощники для заполнения значений по умолчанию вместо пустых / нулевых.

Взгляните, например, на SetObjectDefaults_Deployment для развертывания.

Похоже, его можно вызвать через (*runtime.Scheme).Default. Ниже приведен фрагмент, демонстрирующий общую идею:

import (
    "reflect"

    appsv1 "k8s.io/api/apps/v1"
    "k8s.io/client-go/kubernetes/scheme"
)

func compare() {
    scheme := scheme.Scheme

    // fetch the existing &appsv1.Deployment via API
    actual := ...
    expected := &appsv1.Deployment{}

    // fill in the fields to generate your expected state
    // ...

    scheme.Default(expected)
    // now you should have your empty values filled in
    if !reflect.DeepEqual(expected.Spec, actual.Spec) {
        reconcile(expected, actual)
    }
}

Если вам нужно менее строгое сравнение, например, если вам нужно терпеть некоторые внедренные контейнеры, следует использовать что-то более расслабленное, например это.

person Nick Revin    schedule 17.05.2019