timestamp_duration/
timestamp_duration.rs1use kube_cel::{compile_schema, validate, validate_compiled};
6use serde_json::json;
7
8fn main() {
9 let schema = json!({
11 "type": "object",
12 "properties": {
13 "spec": {
14 "type": "object",
15 "properties": {
16 "expiresAt": {
17 "type": "string",
18 "format": "date-time"
19 },
20 "timeout": {
21 "type": "string",
22 "format": "duration"
23 }
24 },
25 "x-kubernetes-validations": [
26 {
27 "rule": "self.expiresAt > timestamp('2024-01-01T00:00:00Z')",
28 "message": "must expire after 2024-01-01"
29 },
30 {
31 "rule": "self.timeout <= duration('1h')",
32 "message": "timeout must be at most 1 hour"
33 }
34 ]
35 }
36 }
37 });
38
39 println!("=== Schema-based validation ===\n");
42
43 let valid = json!({
44 "spec": {
45 "expiresAt": "2025-06-15T12:00:00Z",
46 "timeout": "30m"
47 }
48 });
49 match validate(&schema, &valid, None) {
50 Ok(()) => println!("Valid object: OK"),
51 Err(errors) => println!("Valid object: {} errors", errors.len()),
52 }
53
54 let invalid = json!({
55 "spec": {
56 "expiresAt": "2023-06-15T12:00:00Z",
57 "timeout": "2h"
58 }
59 });
60 if let Err(errors) = validate(&schema, &invalid, None) {
61 println!("Invalid object: {} errors", errors.len());
62 for err in &errors {
63 println!(" [{path}] {msg}", path = err.field_path, msg = err.message);
64 }
65 }
66
67 println!("\n=== Compiled schema validation ===\n");
70
71 let compiled = compile_schema(&schema);
72
73 let objects = [
74 json!({"spec": {"expiresAt": "2025-01-01T00:00:00Z", "timeout": "30s"}}),
75 json!({"spec": {"expiresAt": "2023-12-31T23:59:59Z", "timeout": "45m"}}),
76 json!({"spec": {"expiresAt": "2025-06-15T00:00:00Z", "timeout": "90m"}}),
77 ];
78
79 for (i, obj) in objects.iter().enumerate() {
80 match validate_compiled(&compiled, obj, None) {
81 Ok(()) => println!("Object {i}: OK"),
82 Err(errors) => {
83 println!("Object {i}: {} error(s)", errors.len());
84 for err in &errors {
85 println!(" [{path}] {msg}", path = err.field_path, msg = err.message);
86 }
87 }
88 }
89 }
90
91 println!("\n=== Transition rule (expiration cannot move earlier) ===\n");
94
95 let transition_schema = json!({
96 "type": "object",
97 "properties": {
98 "expiresAt": {
99 "type": "string",
100 "format": "date-time"
101 }
102 },
103 "x-kubernetes-validations": [{
104 "rule": "self.expiresAt >= oldSelf.expiresAt",
105 "message": "expiration cannot be moved earlier"
106 }]
107 });
108
109 let new_obj = json!({"expiresAt": "2025-12-01T00:00:00Z"});
110 let old_obj = json!({"expiresAt": "2025-06-01T00:00:00Z"});
111
112 match validate(&transition_schema, &new_obj, Some(&old_obj)) {
113 Ok(()) => println!("Extend expiration: OK"),
114 Err(errors) => println!("Extend expiration: {} errors", errors.len()),
115 }
116
117 let bad_obj = json!({"expiresAt": "2025-01-01T00:00:00Z"});
118 if let Err(errors) = validate(&transition_schema, &bad_obj, Some(&old_obj)) {
119 println!("Shorten expiration: {} errors", errors.len());
120 for err in &errors {
121 println!(" {err}");
122 }
123 }
124}