Este documento ha sido traducido utilizando tecnología de traducción automática. Si bien nos esforzamos por proporcionar traducciones precisas, no ofrecemos garantías sobre la integridad, precisión o confiabilidad del contenido traducido. En caso de discrepancia, la versión original en inglés prevalecerá y constituirá el texto autorizado.

Esta es documentación inédita para Admission Controller 1.34-dev.

Validación utilizando consultas JSON

Una sección anterior muestra cómo escribir una
validación
directiva utilizando tipos de Go que describen objetos de Kubernetes.

Hay otra forma de escribir la lógica de validación, extrayendo los datos relevantes del documento JSON utilizando consultas ad-hoc.

Este enfoque "similar a jq" puede ser útil cuando la directiva tiene que mirar profundamente dentro de un objeto de Kubernetes. Es especialmente útil al tratar con objetos internos opcionales.

Este documento reimplementa el código anterior utilizando consultas JSON en lugar de deserializar la carga JSON en tipos de Go.

La validate función

Puedes utilizar la directiva que acabas de crear y cambiar su validate función para no usar los tipos de Go que definen objetos de Kubernetes.

Puedes en su lugar utilizar la gjson biblioteca para extraer datos del objeto JSON crudo.

Primero, necesitas cambiar la sección de requisitos. Así es como debería verse el código:

import (
    "encoding/json"
    "fmt"

    mapset "github.com/deckarep/golang-set/v2"
    kubewarden "github.com/kubewarden/policy-sdk-go"
    kubewarden_protocol "github.com/kubewarden/policy-sdk-go/protocol"
    "github.com/tidwall/gjson"
)

Cambia la validate función para que se parezca a:

validate función
func validate(payload []byte) ([]byte, error) {
    // Create a ValidationRequest instance from the incoming payload
    validationRequest := kubewarden_protocol.ValidationRequest{}
    err := json.Unmarshal(payload, &validationRequest)
    if err != nil {
        return kubewarden.RejectRequest(
            kubewarden.Message(err.Error()),
            kubewarden.Code(400))
    }

    // Create a Settings instance from the ValidationRequest object
    settings, err := NewSettingsFromValidationReq(&validationRequest)
    if err != nil {
        return kubewarden.RejectRequest(
            kubewarden.Message(err.Error()),
            kubewarden.Code(400))
    }

    // Access the **raw** JSON that describes the object
    podJSON := validationRequest.Request.Object

    // NOTE 1
    data := gjson.GetBytes(
        podJSON,
        "metadata.labels")

    var validationErr error
    labels := mapset.NewThreadUnsafeSet[string]()
    data.ForEach(func(key, value gjson.Result) bool {
        // NOTE 2
        label := key.String()
        labels.Add(label)

        // NOTE 3
        validationErr = validateLabel(label, value.String(), &settings)

        // keep iterating if there are no errors
        return validationErr == nil
    })

    // NOTE 4
    if validationErr != nil {
        return kubewarden.RejectRequest(
            kubewarden.Message(validationErr.Error()),
            kubewarden.NoCode)
    }

    // NOTE 5
    for requiredLabel := range settings.ConstrainedLabels {
        if !labels.Contains(requiredLabel) {
            return kubewarden.RejectRequest(
                kubewarden.Message(fmt.Sprintf("Constrained label %s not found inside of Pod", requiredLabel)),
                kubewarden.NoCode)
        }
    }

    return kubewarden.AcceptRequest()
}

La primera parte de la validate función es similar a antes. Las notas marcan los cambios.

  1. Utilizas un gjson selector para obtener el label mapa proporcionado por el objeto incrustado en la solicitud

  2. Utilizas un gjson helper para iterar sobre los resultados de la consulta. Si la consulta no tiene resultados, el bucle nunca se lleva a cabo.

  3. Utilizas la validateLabel función para validar la etiqueta y su valor, como antes. También estás añadiendo las etiquetas encontradas en el Pod a un mapset.Set previamente definido.

  4. Si la validación produce un error, devuelves inmediatamente una respuesta de rechazo de validación.

  5. Como antes, iteras sobre el constrainedLabels para comprobar que todos están especificados en el Pod. El código ha sido ligeramente modificado para hacer uso del mapset.Set previamente poblado.

Probando el código de validación

Las pruebas unitarias y las pruebas de extremo a extremo no necesitan ningún cambio, puedes ejecutarlas como antes:

make test
go test -v
=== RUN   TestParseValidSettings
--- PASS: TestParseValidSettings (0.00s)
=== RUN   TestParseSettingsWithInvalidRegexp
--- PASS: TestParseSettingsWithInvalidRegexp (0.00s)
=== RUN   TestDetectValidSettings
--- PASS: TestDetectValidSettings (0.00s)
=== RUN   TestDetectNotValidSettingsDueToBrokenRegexp
--- PASS: TestDetectNotValidSettingsDueToBrokenRegexp (0.00s)
=== RUN   TestDetectNotValidSettingsDueToConflictingLabels
--- PASS: TestDetectNotValidSettingsDueToConflictingLabels (0.00s)
=== RUN   TestValidateLabel
--- PASS: TestValidateLabel (0.00s)
PASS
ok      github.com/kubewarden/go-policy-template    0.002s
make e2e-tests
bats e2e.bats
e2e.bats
 ✓ accept when no settings are provided
 ✓ accept because label is satisfying a constraint
 ✓ accept labels are not on deny list
 ✓ reject because label is on deny list
 ✓ reject because label is not satisfying a constraint
 ✓ reject because constrained label is missing
 ✓ fail settings validation because of conflicting labels
 ✓ fail settings validation because of invalid constraint

8 tests, 0 failures

Todas las pruebas están funcionando como se esperaba.