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
| `minReplicas <= replicas <= maxReplicas` | Validate that the three fields defining replicas are ordered appropriately |
234
-
| `'Available' in stateCounts` | Validate the 'Available' key exists in a map |
235
-
| `(size(list1) == 0) != (size(list2) == 0)` | Validate that one of two lists is non-empty, but not both |
236
-
| `created + ttl < expiry` | Validate that 'expiry' date is after a 'create' date plus a 'ttl' duration |
237
-
| `health.startsWith('ok')` | Validate a 'health' string field has the prefix 'ok' |
238
-
| `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 |
239
-
| `type(limit) == string ? limit == '100%' : limit == 1000` | Validate an int-or-string field for both the the int and string cases |
240
-
| `metadata.name == 'singleton` | Validate that an object's name matches a specific value (making it a singleton) |
241
-
| `set1.all(e, !(e in set2))` | Validate that two listSets are disjoint |
242
-
| `size(names) == size(details) && names.all(n, n in details)` | Validate the 'details' map is keyed by the items in the names listSet |
230
+
| Rule | Purpose |
231
+
| ---------------- | ------------ |
232
+
| `self.minReplicas <= 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
+
| `has(self.expired) && self.created + self.ttl < self.expired` | Validate that 'expired' date is after a 'create' date plus a 'ttl' duration |
236
+
| `self.health.startsWith('ok')` | Validate a 'health' string field has the prefix 'ok' |
237
+
| `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 |
238
+
| `type(self.limit) == string ? self.limit == '100%' : self.limit == 1000` | Validate an int-or-string field for both the the int and string cases |
239
+
| `self.metadata.name == 'singleton` | Validate that an object's name matches a specific value (making it a singleton) |
240
+
| `self.set1.all(e, !(e in self.set2))` | Validate that two listSets are disjoint |
241
+
| `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 |
243
242
244
243
245
244
- Each validator may have multiple validation rules.
@@ -279,39 +278,34 @@ is scoped to.
279
278
280
279
It will cause a lot of keywords to be reserved and users have to memorize those variable when writing rules.
281
280
- Using other names like `this`, `me`, `value`, `_`. The name should be self-explanatory, less chance of conflict and easy to be picked up.
282
-
- For OpenAPIv3 object types, the expression will have direct access to all the
283
-
fields of the object the validator is scoped to.
281
+
282
+
- For OpenAPIv3 object types, the expression may use field selection to access all the
283
+
properties of the object the validator is scoped to, e.g. `self.field == 10`.
284
284
285
285
- For OpenAPIv3 scalar types (integer, string & boolean), the expression will have access to the
286
-
scalar data element the validator is scoped to. The data element will be accessible to CEL
287
-
expressions via `self`, e.g. `len(self) > 10`.
286
+
scalar data element the validator is scoped to. The data element will be accessible to CEL
287
+
expressions via `self`, e.g. `len(self) > 10`.
288
288
289
289
- For OpenAPIv3 list and map types, the expression will have access to the data element of the list
290
290
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
291
291
like the `all` macro, e.g. `self.all(listItem, <predicate>)` or `self.all(mapKey,
292
292
<predicate>)`.
293
293
294
294
- For immutability use case, validator will have access to the existing version of the object. This
295
-
will be accessible to CEL via the `old<propertyName>` identifier.
295
+
will be accessible to CEL via the `oldSelf` identifier.
296
296
- This will only be available on mergable collection types such as objects (unless
297
297
`x-kubernetes-map-type=atomic`), maps with `x-kubernetes-map-type=granular` and lists
298
298
with `x-kubernetes-list-type` set to `set` or `map`. See [Merge
299
299
Strategy](https://kubernetes.io/docs/reference/using-api/server-side-apply/#merge-strategy) for
300
300
details.
301
301
- The use of "old" is congruent with how `AdmissionReview` identifies the existing object as
302
-
`oldObject`. To avoid name collisions `old<propertyName>` will be treated the same as a CEL
303
-
keyword for escaping purposes (see below).
302
+
`oldObject`.
304
303
- xref [analysis of possible interactions with immutability and
- If a object property name is a CEL keyword (see RESERVED in [CEL Syntax](https://github.com/google/cel-spec/blob/master/doc/langdef.md#syntax)),
308
307
it will be escaped by prepending a _ prefix. To prevent this from causing a subsequent collision, properties named with a CEL keyword and a `_` prefix will be
309
308
prefixed by `__` (generally, N+1 the existing number of `_`s).
310
-
311
-
- If a object property name is a CEL language identifier (`int`, `uint`, `double`, `bool`, `string`,
312
-
`bytes`, `list`, `map`, `null_type`, `type`, see [CEL language
313
-
identifiers](https://github.com/google/cel-spec/blob/master/doc/langdef.md#values)) it is not
314
-
accessible as a root variable and must be accessed via `self`, .e.g. `self.int`.
315
309
316
310
- Only property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible.
317
311
If a property name is "self" or matches with a [reserved language identifier](https://github.com/google/cel-spec/blob/v0.6.0/doc/langdef.md#values)
@@ -330,10 +324,10 @@ like the `all` macro, e.g. `self.all(listItem, <predicate>)` or `self.all(mapKey
330
324
- Rules may be written at the root of an object, and may make field selection into any fields
331
325
declared in the OpenAPIv3 schema of the CRD as well as `apiVersion`, `kind`, `metadata.name` and
332
326
`metadata.generateName`. This includes selection of fields in both the `spec` and `status` in the
333
-
same expression, e.g. `status.quantity <= spec.maxQuantity`. Because CRDs only allow the `name`
327
+
same expression, e.g. `self.status.quantity <= self.spec.maxQuantity`. Because CRDs only allow the `name`
334
328
and `generateName` to be declared in the `metadata` of an object, these are the only metadata
335
329
fields that may be validated using CEL validator rules. For example,
336
-
`metadata.name.endsWith('mySuffix')`is allowed, but `size(metadata.labels) < 3` it not
330
+
`self.metadata.name.endsWith('mySuffix')`is allowed, but `size(self.metadata.labels) < 3` it not
337
331
allowed. The limit on which `metadata` fields may be validated is an intentional design choice
338
332
(that aims to keep metadata behavior uniform across types) and applies to all validation
339
333
mechanisms (e.g. the OpenAPIV3 `maxItems` restriction), not just CEL validator rules.
@@ -349,14 +343,6 @@ like the `all` macro, e.g. `self.all(listItem, <predicate>)` or `self.all(mapKey
A field path is a patch to a single node in the data tree. I.e. it specifies the
355
-
exact indices of the list items and the keys of map entries it traverses.
356
-
357
-
A field *pattern* is a path to all nodes in the data tree that match the pattern. I.e.
358
-
it may wildcard list item and map keys.
359
-
360
346
#### Expression lifecycle
361
347
362
348
When CRDs are written to the kube-apiserver, all expressions will be [parsed and
@@ -584,18 +570,20 @@ The initial changes made in the type integration will be:
584
570
- We couldn't have both: (a) equality of string keys, which implies a canonical ordering of key fields, and (b) ability for developers to successfully lookup a map entry regardless of how they order the keys in the string representation
585
571
586
572
587
-
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) and introduce utility functions to make the list representation easy to use in CEL. E.g. instead of:
573
+
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).
574
+
575
+
Looking up entiries by keys is available primarily via the `exists_one` and `filter` macros. Examples:
0 commit comments