|
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. |
Écriture de la logique de validation
Il est temps d’écrire le code de validation réel.
Il est défini dans le fichier src/lib.rs.
Dans ce fichier, vous pouvez trouver une fonction appelée validate.
Voici la fonction fournie par le scaffolding :
fn validate(payload: &[u8]) -> CallResult {
let validation_request: ValidationRequest<Settings> = ValidationRequest::new(payload)?; (1)
info!(LOG_DRAIN, "starting validation");
if validation_request.request.kind.kind != apicore::Pod::KIND {
warn!(LOG_DRAIN, "Policy validates Pods only. Accepting resource"; "kind" => &validation_request.request.kind.kind);
return kubewarden::accept_request();
}
// TODO: you can unmarshal any Kubernetes API type you are interested in (2)
match serde_json::from_value::<apicore::Pod>(validation_request.request.object) {
Ok(pod) => {
// TODO: your logic goes here (3)
if pod.metadata.name == Some("invalid-pod-name".to_string()) {
let pod_name = pod.metadata.name.unwrap();
info!(
LOG_DRAIN,
"rejecting pod";
"pod_name" => &pod_name
);
kubewarden::reject_request(
Some(format!("pod name {} is not accepted", &pod_name)),
None,
None,
None,
)
} else {
info!(LOG_DRAIN, "accepting resource");
kubewarden::accept_request()
}
}
Err(_) => {
// TODO: handle as you wish
// We were forwarded a request we cannot unmarshal or
// understand, just accept it
warn!(LOG_DRAIN, "cannot unmarshal resource: this policy does not know how to evaluate this resource; accept it");
kubewarden::accept_request() (4)
}
}
}
Parcourons la liste de code :
-
Dans la ligne marquée ➀. Analysez le
payloadentrant en un objetValidationRequest<Setting>. Cela remplit automatiquement l’instanceSettingsà l’intérieur deValidationRequestavec les paramètres fournis par l’utilisateur. -
Dans la ligne marquée ➁. Convertissez l’objet JSON brut Kubernetes intégré dans la requête en une instance de la structure Pod struct
-
Dans la ligne marquée ➂. La requête contient un objet Pod, le code n’approuve que les requêtes qui n’ont pas
metadata.nameégal à la valeur codée en durinvalid-pod-name. -
Dans la ligne marquée ➃. La requête ne contient pas d’objet Pod, donc la stratégie accepte la requête.
Comme vous pouvez le voir, le code effectue déjà une validation qui ressemble à celle que vous souhaitez mettre en œuvre. Vous devez simplement supprimer la valeur codée en dur et utiliser les valeurs fournies par l’utilisateur via les paramètres de la stratégie.
Vous pouvez le faire en remplaçant la fonction de scaffolding validate dans src/lib.rs par celle-ci :
fn validate(payload: &[u8]) -> CallResult {
let validation_request: ValidationRequest<Settings> = ValidationRequest::new(payload)?;
info!(LOG_DRAIN, "starting validation");
if validation_request.request.kind.kind != apicore::Pod::KIND {
warn!(LOG_DRAIN, "Policy validates Pods only. Accepting resource"; "kind" => &validation_request.request.kind.kind);
return kubewarden::accept_request();
}
match serde_json::from_value::<apicore::Pod>(validation_request.request.object) {
Ok(pod) => {
let pod_name = pod.metadata.name.unwrap_or_default();
if validation_request
.settings
.invalid_names
.contains(&pod_name)
{
kubewarden::reject_request(
Some(format!("pod name {:?} is not accepted", pod_name)),
None,
None,
None,
)
} else {
kubewarden::accept_request()
}
}
Err(_) => {
// We were forwarded a request we cannot unmarshal or
// understand, just accept it
kubewarden::accept_request()
}
}
}
Tests unitaires
Enfin, vous pouvez créer des tests unitaires pour vérifier que le code de validation fonctionne comme prévu.
Le fichier lib.rs a déjà des tests définis en bas du fichier, et comme vous pouvez le voir, le SDK Rust de Admission Controller fournit également des helpers de test.
De plus, le projet de scaffolding est déjà livré avec des fixtures de test par défaut dans le répertoire test_data. Vous allez utiliser ces demandes d’admission enregistrées pour écrire vos tests unitaires.
Modifiez le contenu de la section de test à la fin de src/lib.rs pour qu’il ressemble à ceci :
#[cfg(test)]
mod tests {
use super::*;
use kubewarden_policy_sdk::test::Testcase;
use std::collections::HashSet;
#[test]
fn accept_pod_with_valid_name() -> Result<(), ()> {
let mut invalid_names = HashSet::new();
invalid_names.insert(String::from("bad_name1"));
let settings = Settings { invalid_names };
let request_file = "test_data/pod_creation.json";
let tc = Testcase {
name: String::from("Pod creation with valid name"),
fixture_file: String::from(request_file),
expected_validation_result: true,
settings,
};
let res = tc.eval(validate).unwrap();
assert!(
res.mutated_object.is_none(),
"Something mutated with test case: {}",
tc.name,
);
Ok(())
}
#[test]
fn reject_pod_with_invalid_name() -> Result<(), ()> {
let mut invalid_names = HashSet::new();
invalid_names.insert(String::from("nginx"));
let settings = Settings { invalid_names };
let request_file = "test_data/pod_creation.json";
let tc = Testcase {
name: String::from("Pod creation with invalid name"),
fixture_file: String::from(request_file),
expected_validation_result: false,
settings,
};
let res = tc.eval(validate).unwrap();
assert!(
res.mutated_object.is_none(),
"Something mutated with test case: {}",
tc.name,
);
Ok(())
}
#[test]
fn accept_request_with_non_pod_resource() -> Result<(), ()> {
let mut invalid_names = HashSet::new();
invalid_names.insert(String::from("prod"));
let settings = Settings { invalid_names };
let request_file = "test_data/ingress_creation.json";
let tc = Testcase {
name: String::from("Ingress creation"),
fixture_file: String::from(request_file),
expected_validation_result: true,
settings,
};
let res = tc.eval(validate).unwrap();
assert!(
res.mutated_object.is_none(),
"Something mutated with test case: {}",
tc.name,
);
Ok(())
}
}
Vous avez maintenant trois tests unitaires définis dans lib.rs :
-
accept_pod_with_valid_name: accepte un Pod avec un nom valide -
reject_pod_with_invalid_name: rejette un Pod avec un nom invalide -
accept_request_with_non_pod_resource: accepte les demandes qui n’ont pas unPoden tant qu’objet
Vous pouvez exécuter à nouveau les tests unitaires :
$ cargo test
Compiling demo v0.1.0 (/home/flavio/hacking/kubernetes/kubewarden/demo)
Finished test [unoptimized + debuginfo] target(s) in 3.45s
Running target/debug/deps/demo-24670dd6a538fd72
running 5 tests
test settings::tests::accept_settings_with_a_list_of_invalid_names ... ok
test settings::tests::reject_settings_without_a_list_of_invalid_names ... ok
test tests::accept_request_with_non_pod_resource ... ok
test tests::accept_pod_with_valid_name ... ok
test tests::reject_pod_with_invalid_name ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
C’est tout ce qui est requis si vous devez écrire une stratégie de validation simple.