You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| `self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas` | Validate that the three fields defining replicas are ordered appropriately |
233
-
| `'Available' in self.stateCounts` | Validate that an entry with the 'Available' key exists in a map |
234
-
| `(size(self.list1) == 0) != (size(self.list2) == 0)` | Validate that one of two lists is non-empty, but not both |
235
-
| `!('MY_KEY' in self.map1) || self['MY_KEY].matches('^[a-zA-Z]*$')` | Validate the value of a map for a specific key, if it is in the map |
236
-
| `self.envars.filter(e, e.name = 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')` | Validate the 'value' field of a listMap entry where key field 'name' is 'MY_ENV' |
237
-
| `has(self.expired) && self.created + self.ttl < self.expired` | Validate that 'expired' date is after a 'create' date plus a 'ttl' duration |
238
-
| `self.health.startsWith('ok')` | Validate a 'health' string field has the prefix 'ok' |
239
-
| `self.widgets.exists(w, w.key == 'x' && w.foo < 10)` | Validate that the 'foo' property of a listMap item with a key 'x' is less than 10 |
240
-
| `type(self) == string ? self == '100%' : self == 1000` | Validate an int-or-string field for both the the int and string cases |
241
-
| `self.metadata.name == 'singleton'` | Validate that an object's name matches a specific value (making it a singleton) |
242
-
| `self.set1.all(e, !(e in self.set2))` | Validate that two listSets are disjoint |
243
-
| `size(self.names) == size(self.details) && self.names.all(n, n in self.details)` | Validate the 'details' map is keyed by the items in the 'names' listSet |
230
+
| Rule | Purpose |
231
+
| ---------------- | ------------ |
232
+
| `self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas` | Validate that the three fields defining replicas are ordered appropriately |
233
+
| `'Available' in self.stateCounts` | Validate that an entry with the 'Available' key exists in a map |
234
+
| `(self.list1.size() == 0) != self.list2.size() == 0)` | Validate that one of two lists is non-empty, but not both |
235
+
| `!('MY_KEY' in self.map1) \|\| self['MY_KEY'].matches('^[a-zA-Z]*$')` | Validate the value of a map for a specific key, if it is in the map |
236
+
| `self.envars.filter(e, e.name = 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')` | Validate the 'value' field of a listMap entry where key field 'name' is 'MY_ENV' |
237
+
| `has(self.expired) && self.created + self.ttl < self.expired` | Validate that 'expired' date is after a 'create' date plus a 'ttl' duration |
238
+
| `self.health.startsWith('ok')` | Validate a 'health' string field has the prefix 'ok' |
239
+
| `self.widgets.exists(w, w.key == 'x' && w.foo < 10)` | Validate that the 'foo' property of a listMap item with a key 'x' is less than 10 |
240
+
| `type(self) == string ? self == '100%' : self == 1000` | Validate an int-or-string field for both the the int and string cases |
241
+
| `self.metadata.name == 'singleton'` | Validate that an object's name matches a specific value (making it a singleton) |
242
+
| `self.set1.all(e, !(e in self.set2))` | Validate that two listSets are disjoint |
243
+
| `self.names.size() == self.details.size() && self.names.all(n, n in self.details)` | Validate the 'details' map is keyed by the items in the 'names' listSet |
244
244
245
245
246
246
- Each validator may have multiple validation rules.
@@ -286,7 +286,7 @@ is scoped to.
286
286
287
287
- For OpenAPIv3 scalar types (integer, string & boolean), the expression will have access to the
288
288
scalar data element the validator is scoped to. The data element will be accessible to CEL
289
-
expressions via `self`, e.g. `len(self) > 10`.
289
+
expressions via `self`, e.g. `self.size() > 10`.
290
290
291
291
- For OpenAPIv3 list and map types, the expression will have access to the data element of the list
292
292
or map. These will be accessible to CEL via `self`. The elements of a map or list can be validated using the CEL support for collections
@@ -321,7 +321,7 @@ like the `all` macro, e.g. `self.all(listItem, <predicate>)` or `self.all(mapKey
321
321
same expression, e.g. `self.status.quantity <= self.spec.maxQuantity`. Because CRDs only allow the
322
322
`name`and `generateName` to be declared in the `metadata` of an object, these are the only
323
323
metadata fields that may be validated using CEL validator rules. For example,
324
-
`self.metadata.name.endsWith('mySuffix')`is allowed, but `size(self.metadata.labels) < 3` it not
324
+
`self.metadata.name.endsWith('mySuffix')`is allowed, but `self.metadata.labels.size() < 3` it not
325
325
allowed. The limit on which `metadata` fields may be validated is an intentional design choice
326
326
(that aims to allow for generic access to labels and annotations across all kinds) and applies to
327
327
all validation mechanisms (e.g. the OpenAPIV3 `maxItems` restriction), not just CEL validator
| 'object' with Properties | object / "message type" |
505
+
| 'object' with Properties | object / "message type" (`type(<object>)` evaluates to `selfType<uniqueNumber>.path.to.object.from.self` |
506
506
| 'object' with AdditionalProperties | map |
507
507
| 'object' with x-kubernetes-embedded-type | object / "message type", 'apiVersion', 'kind', 'metadata.name' and 'metadata.generateName' are implicitly included in schema |
508
508
| 'object' with x-kubernetes-preserve-unknown-fields | object / "message type", unknown fields are NOT accessible in CEL expression |
@@ -513,6 +513,7 @@ Types:
513
513
| 'boolean' | boolean |
514
514
| 'number' (all formats) | double |
515
515
| 'integer' (all formats) | int (64) |
516
+
| <no equivalent> | uint (64) |
516
517
| 'null' | null_type |
517
518
| 'string' | string |
518
519
| 'string' with format=byte (base64 encoded) | bytes |
@@ -567,17 +568,25 @@ The initial changes made in the type integration will be:
567
568
568
569
So instead of treating "associative lists" as maps in CEL, we will continue to treat them as lists, but override equality to ignore object order (i.e. use map equality semantics).
569
570
570
-
Looking up entiries by keys is available primarily via the `exists_one` and `filter` macros. Examples:
571
+
Looking up and iterating over entiries is available via the `exists`, `exists_one` and `all` macros:
571
572
572
573
```
573
-
// exists_one() and exists() behave similarly if all map keys are checked, but exists_one() has slightly stricter
574
-
// semantics, which make it preferable
574
+
// Since there is already a guarantee that "associative lists" only one entry
575
+
// exists in the list for each key, `exists` can be used to check if a map contains a particular key instead of `exists_one`.
576
+
// Note that `exists_one` can also be used, but handles any errors encountered more strictly.
577
+
// See the CEL language spec how errors are handled by `exists_one` and `exists` for more details.
575
578
576
-
// To check if the map contains a entry with a particular key:
0 commit comments