Este documento foi traduzido usando tecnologia de tradução automática de máquina. Sempre trabalhamos para apresentar traduções precisas, mas não oferecemos nenhuma garantia em relação à integridade, precisão ou confiabilidade do conteúdo traduzido. Em caso de qualquer discrepância, a versão original em inglês prevalecerá e constituirá o texto official.

Esta é uma documentação não divulgada para Admission Controller 1.34-dev.

Validação usando consultas JSON

Uma seção anterior mostra como escrever uma validação política usando tipos Go que descrevem objetos Kubernetes.

Há outra maneira de escrever a lógica de validação, extraindo os dados relevantes do documento JSON usando consultas ad-hoc.

Essa abordagem "semelhante ao jq" pode ser útil quando a política precisa olhar profundamente dentro de um objeto Kubernetes. É especialmente útil ao lidar com objetos internos opcionais.

Este documento reimplementa o código anterior usando consultas JSON em vez de deserializar a carga JSON em tipos Go.

A validate função

Você pode usar a política que acabou de criar e mudar sua validate função para não usar os tipos Go que definem objetos Kubernetes.

Você pode em vez disso usar a gjson biblioteca para extrair dados do objeto JSON bruto.

Primeiramente, você precisa mudar a seção de requisitos. É assim que o código deve parecer:

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"
)

Mude a validate função para parecer com:

validate função
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()
}

A primeira parte da validate função é semelhante à anterior. As notas marcam as mudanças.

  1. Você usa um gjson seletor para obter o label mapa fornecido pelo objeto embutido na solicitação

  2. Você usa um gjson auxiliar para iterar sobre os resultados da consulta. Se a consulta não tiver resultados, o loop nunca ocorre.

  3. Você usa a função validateLabel para validar o rótulo e seu valor, como antes. Você também está adicionando os rótulos encontrados no Pod a um mapset.Set previamente definido.

  4. Se a validação produzir um erro, você retorna imediatamente com uma resposta de rejeição de validação.

  5. Como antes, você itera sobre o constrainedLabels para verificar se todos estão especificados no Pod. O código foi levemente alterado para utilizar o mapset.Set previamente preenchido.

Testando o código de validação

Os testes unitários e os testes de ponta a ponta não precisam de nenhuma alteração, você pode executá-los 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

Todos os testes estão funcionando como esperado.