container_device_interface/internal/validation/k8s/
objectmeta.rs1use anyhow::{Error, Result};
2use std::collections::BTreeMap;
3
4const TOTAL_ANNOTATION_SIZE_LIMIT: usize = 256 * 1024; use super::validation::is_qualified_name;
7
8pub fn validate_annotations(annotations: &BTreeMap<String, String>, path: &str) -> Result<()> {
9 let mut errs = Vec::new();
10
11 for k in annotations.keys() {
12 for msg in is_qualified_name(&k.to_lowercase()) {
13 errs.push(format!("{}.{} is invalid: {}", path, k, msg));
14 }
15 }
16
17 if let Err(err) = validate_annotations_size(annotations) {
18 errs.push(format!("{} is too long: {}", path, err));
19 }
20
21 if errs.is_empty() {
22 Ok(())
23 } else {
24 Err(Error::msg(errs.join(", ")))
25 }
26}
27
28fn validate_annotations_size(annotations: &BTreeMap<String, String>) -> Result<()> {
29 let total_size: usize = annotations.iter().map(|(k, v)| k.len() + v.len()).sum();
30
31 if total_size > TOTAL_ANNOTATION_SIZE_LIMIT {
32 Err(Error::msg(format!(
33 "annotations size {} is larger than limit {}",
34 total_size, TOTAL_ANNOTATION_SIZE_LIMIT
35 )))
36 } else {
37 Ok(())
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use super::super::super::validate::validate_spec_annotations;
44 use super::validate_annotations;
45
46 use std::collections::BTreeMap;
47
48 #[test]
49 fn test_validate_annotations() {
50 let mut annotations = BTreeMap::new();
51 annotations.insert(
52 "cdi.k8s.io/vfio17".to_string(),
53 "nvidia.com/gpu=0".to_string(),
54 );
55 annotations.insert(
56 "cdi.k8s.io/vfio18".to_string(),
57 "nvidia.com/gpu=1".to_string(),
58 );
59 annotations.insert(
60 "cdi.k8s.io/vfio19".to_string(),
61 "nvidia.com/gpu=all".to_string(),
62 );
63 let path = "test.annotations";
64
65 assert!(validate_annotations(&annotations, path).is_ok());
66
67 let mut large_annotations = BTreeMap::new();
68 let long_value = "CDI".repeat(super::TOTAL_ANNOTATION_SIZE_LIMIT + 1);
69 large_annotations.insert("CDIKEY".to_string(), long_value);
70 assert!(validate_annotations(&large_annotations, path).is_err());
71
72 let mut invalid_annotations = BTreeMap::new();
73 invalid_annotations.insert(
74 "inv$$alid_CDIKEY".to_string(),
75 "inv$$alid_CDIVAL".to_string(),
76 );
77 assert!(validate_annotations(&invalid_annotations, path).is_err());
78 }
79
80 #[test]
81 fn test_validate_spec_annotations() {
82 let mut annotations = BTreeMap::new();
83 annotations.insert(
84 "cdi.k8s.io/vfio17".to_string(),
85 "nvidia.com/gpu=0".to_string(),
86 );
87 annotations.insert(
88 "cdi.k8s.io/vfio18".to_string(),
89 "nvidia.com/gpu=1".to_string(),
90 );
91 annotations.insert(
92 "cdi.k8s.io/vfio19".to_string(),
93 "nvidia.com/gpu=all".to_string(),
94 );
95
96 assert!(validate_spec_annotations("", &annotations).is_ok());
97 assert!(validate_spec_annotations("CDITEST", &annotations).is_ok());
98
99 let mut large_annotations = BTreeMap::new();
100 let long_value = "CDI".repeat(super::TOTAL_ANNOTATION_SIZE_LIMIT + 1);
101 large_annotations.insert("CDIKEY".to_string(), long_value);
102 assert!(validate_spec_annotations("", &large_annotations).is_err());
103
104 let mut invalid_annotations = BTreeMap::new();
105 invalid_annotations.insert(
106 "inva$$lid_CDIKEY".to_string(),
107 "inval$$id_CDIVAL".to_string(),
108 );
109 assert!(validate_spec_annotations("CDITEST", &invalid_annotations).is_err());
110 }
111}