Ce document a été traduit à l'aide d'une technologie de traduction automatique. Bien que nous nous efforcions de fournir des traductions exactes, nous ne fournissons aucune garantie quant à l'exhaustivité, l'exactitude ou la fiabilité du contenu traduit. En cas de divergence, la version originale anglaise prévaut et fait foi.

Il s'agit d'une documentation non publiée pour Admission Controller 1.34-dev.

Validation à l’aide de requêtes JSON

Une section précédente montre comment écrire une validation stratégie en utilisant des types Go décrivant des objets Kubernetes.

Il existe une autre façon d’écrire la logique de validation, en extrayant les données pertinentes du document JSON à l’aide de requêtes ad hoc.

Cette approche "jq-like" peut être utile lorsque la stratégie doit examiner en profondeur un objet Kubernetes. C’est particulièrement utile lors de la gestion d’objets internes optionnels.

Ce document réimplémente le code précédent en utilisant des requêtes JSON au lieu de désérialiser la charge JSON en types Go.

La validate fonction

Vous pouvez utiliser la stratégie que vous venez de créer et changer sa validate fonction pour ne pas utiliser les types Go qui définissent les objets Kubernetes.

Vous pouvez plutôt utiliser la gjson bibliothèque pour extraire des données de l’objet JSON brut.

Tout d’abord, vous devez modifier la section des exigences. Voici à quoi le code devrait ressembler :

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

Changez la validate fonction pour qu’elle ressemble à :

validate fonction
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 première partie de la validate fonction est similaire à celle d’avant. Les 'NOTE' indiquent les changements.

  1. Vous utilisez un sélecteur gjson pour obtenir la carte label fournie par l’objet intégré dans la requête

  2. Vous utilisez un helper gjson pour itérer sur les résultats de la requête. Si la requête ne donne aucun résultat, la boucle ne se produit jamais.

  3. Vous utilisez la fonction validateLabel pour valider l’étiquette et sa valeur, comme auparavant. Vous ajoutez également les étiquettes trouvées dans le Pod à un mapset.Set précédemment défini.

  4. Si la validation a produit une erreur, vous retournez immédiatement avec une réponse de rejet de validation.

  5. Comme auparavant, vous itérez sur le constrainedLabels pour vérifier que tous sont spécifiés dans le Pod. Le code a été légèrement modifié pour utiliser le mapset.Set précédemment rempli.

Test de la validation du code

Les tests unitaires et les tests de bout en bout n’ont besoin d’aucun changement, vous pouvez les exécuter comme auparavant :

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

Tous les tests fonctionnent comme prévu.