Есть ли в клиентской библиотеке Kubernetes функция для проверки файлов json/yaml?

Я хотел бы знать, содержит ли библиотека client-go для Kubernetes функцию, которая проверяет наличие файла json / yaml. В идеале, он будет отлавливать ошибки, такие как имена, не соответствующие DNS-1123, или указанные неверные поля. Также было бы идеально, если бы был возвращен список ошибок, а не функция, возвращающаяся после первой обнаруженной ошибки.

Одна мысль, которую я пытался сделать, это выполнить exec для вызова kubectl --validate --dry-run но это не полностью проверяет манифест (то есть, его можно пропустить, но потерпеть неудачу, когда вы на самом деле примените файл). Это также останавливается при первой ошибке. Плюс, это быстро обойдется, если у вас есть список манифестов, чтобы пройти.

Другой вариант, на который я посмотрел, был здесь Kubernetes GitHub Issue 193, но это не совсем подходящая функция и не выполняет те проверки, которые я ищу.

2 ответа

Клиентская библиотека для Kubernetes не содержит функций проверки для файлов конфигурации YAML/JSON.

Но взгляните на это, вы можете использовать его для проверки на стороне клиента, а также использовать его код в качестве примера реализации проверки.

Ты можешь взятьk8s.io/kubernetes/pkg/apis/apps/validationиk8s.io/kubernetes/pkg/apis/core/validationиспользуя этот скрипт:

      #!/bin/sh
set -euo pipefail

VERSION=${1#"v"}
if [ -z "$VERSION" ]; then
    echo "Must specify version!"
    exit 1
fi
MODS=($(
    curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod |
    sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p'
))
for MOD in "${MODS[@]}"; do
    V=$(
        go mod download -json "${MOD}@kubernetes-${VERSION}" |
        sed -n 's|.*"Version": "\(.*\)".*|\1|p'
    )
    go mod edit "-replace=${MOD}=${MOD}@${V}"
done
go get "k8s.io/kubernetes@v${VERSION}"

Затем вы можете написать такой тест для проверки манифеста с помощьюServiceиDeployment:

      import (
    "github.com/stretchr/testify/assert"
    appsV1 "k8s.io/api/apps/v1"
    coreV1 "k8s.io/api/core/v1"
    "k8s.io/client-go/kubernetes/scheme"
    kubernetesApps "k8s.io/kubernetes/pkg/apis/apps"
    kubernetesAppsV1 "k8s.io/kubernetes/pkg/apis/apps/v1"
    kubernetesAppsValidation "k8s.io/kubernetes/pkg/apis/apps/validation"
    kubernetesCore "k8s.io/kubernetes/pkg/apis/core"
    kubernetesCoreV1 "k8s.io/kubernetes/pkg/apis/core/v1"
    kubernetesCoreValidation "k8s.io/kubernetes/pkg/apis/core/validation"
    "strings"
    "testing"
    "text/template"
)

const RedisTemplate = `
---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  type: ClusterIP
  internalTrafficPolicy: Cluster
  sessionAffinity: None
  ports:
  - name: redis-port
    protocol: TCP
    port: 6379
    targetPort: 6379
--- 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
....
`

func Test_RedisManifest(t *testing.T) {
    for _, m := range strings.Split(RedisTemplate, "---") {
        if len(strings.Trim(m, "\n")) == 0 {
            continue
        }

        obj, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(m), nil, nil)
        assert.NoError(t, err)
        assert.NotEmptyf(t, obj.GetObjectKind().GroupVersionKind().Kind, "parsed k8s object kind is empty")

        if service, ok := obj.(*coreV1.Service); ok {
            kubernetesService := &kubernetesCore.Service{}
            conversionErr := kubernetesCoreV1.Convert_v1_Service_To_core_Service(service, kubernetesService, nil)
            assert.NoError(t, conversionErr)
            kubernetesService.ObjectMeta.Namespace = "default"
            validationErrs := kubernetesCoreValidation.ValidateService(kubernetesService)
            assert.Empty(t, validationErrs)

        }

        if deployment, ok := obj.(*appsV1.Deployment); ok {
            kubernetesDeployment := &kubernetesApps.Deployment{}
            conversionErr := kubernetesAppsV1.Convert_v1_Deployment_To_apps_Deployment(deployment, kubernetesDeployment, nil)
            assert.NoError(t, conversionErr)

            kubernetesDeployment.ObjectMeta.Namespace = "default"
            validationErrs := kubernetesAppsValidation.ValidateDeployment(kubernetesDeployment, kubernetesCoreValidation.PodValidationOptions{})
            assert.Empty(t, validationErrs)
        }
    }
}

В этом подходе я вижу следующие недостатки:

  1. Прямой импорт не рекомендуется командой K8s.
  2. Прямой импортk8s.io/kubernetesможет создать проблемы в будущем.
  3. Валдационные функцииValidateServiceиValidateDeploymentожидают, что необязательные поля, такие какnamespace,internalTrafficPolicy,sessionAffinityи многие другие должны иметь значения. Возможно, есть какие-то другие функции, которые могут заполнять необязательные поля значениями по умолчанию, но на данный момент я их не нашел.
Другие вопросы по тегам