Skip to content

Commit 371a65c

Browse files
authored
Merge pull request kubernetes#3669 from DangerOnTheRanger/expression-composition-update
KEP-3488: Add information on expression composition
2 parents b6ab8a0 + 49edd50 commit 371a65c

File tree

1 file changed

+67
-6
lines changed
  • keps/sig-api-machinery/3488-cel-admission-control

1 file changed

+67
-6
lines changed

keps/sig-api-machinery/3488-cel-admission-control/README.md

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- [Enforcement Actions](#enforcement-actions)
2929
- [Namespace scoped policy binding](#namespace-scoped-policy-binding)
3030
- [CEL Expression Composition](#cel-expression-composition)
31+
- [Use Cases](#use-cases)
3132
- [Variables](#variables)
3233
- [Secondary Authz](#secondary-authz)
3334
- [Access to namespace metadata](#access-to-namespace-metadata)
@@ -1070,28 +1071,88 @@ Details to consider:
10701071

10711072
#### CEL Expression Composition
10721073

1074+
##### Use Cases
1075+
1076+
###### Code re-use for complicated expressions
1077+
1078+
A CEL expression may not be computationally expensive, but could still be
1079+
intricate enough that copy-pasting could prove to be a bad decision later on
1080+
in time. With the addition of the `messageExpression` field, more copy-pasting
1081+
is expected as well. If a sufficiently complex expression ended up copy-pasted everywhere,
1082+
and then needs to be updated somehow, it will need that update in every place
1083+
it was copy-pasted. A variable, on the other hand, will only need to be updated
1084+
in one place.
1085+
1086+
###### Reusing/memoizing an expensive computation
1087+
1088+
For a CEL expression that runs in O(n^2) time or worse (or otherwise
1089+
takes a significant amount of time to execute), it would be nice to only run
1090+
it when necessary. For instance, if multiple validation expressions used the
1091+
same expensive expression, that expression could be refactored out into a
1092+
variable.
1093+
10731094
##### Variables
10741095

1075-
Each CEL "program" is a single expression. There is no support for vaiable
1096+
Each CEL "program" is a single expression. There is no support for variable
10761097
assignment. This can result in redundant code to traverse maps/arrays or
10771098
dereference particular fields.
10781099

10791100
We can support this in much the same way as cel-policy-template `terms`. These
10801101
can be lazily evaluated while the validation expressions are evaluated
1081-
(cel-policy-template does this). The results can also be memoized to avoid
1082-
repeated evaluations if they are shared across validations.
1102+
(cel-policy-template does this).
1103+
1104+
A policy can include an additional `variables` section. This is an array
1105+
containing one or more `name` and `expression` pairs, which can be used/re-used by
1106+
the policy's validation expressions. These results are memoized on a
1107+
per-validation basis, so if multiple expressions use the same spec variables,
1108+
the expression that calculates the variable's value will only run once.
1109+
1110+
The variables can be accessed as members of `variables`, which is an object
1111+
that is exposed to CEL expressions (both validation expressions as well as
1112+
other variables).
1113+
1114+
For example:
10831115

10841116
```yaml
10851117
variables:
10861118
- name: metadataList
10871119
expression: "spec.list.map(x, x.metadata)"
10881120
- name: itemMetadataNames
1089-
expression: "metadataList.map(m, m.name)"
1121+
expression: "variables.metadataList.map(m, m.name)"
10901122
validations:
1091-
- expression: "itemMetadataNames.all(name, name.startsWith('xyz-'))"
1092-
- expression: "itemMetadataNames.exists(name, name == 'required')"
1123+
- expression: "variables.itemMetadataNames.all(name, name.startsWith('xyz-'))"
1124+
- expression: "variables.itemMetadataNames.exists(name, name == 'required')"
10931125
```
10941126

1127+
Variable names must be valid CEL names. What constitutes a
1128+
valid CEL name can be found at CEL's [language definition](https://github.com/google/cel-spec/blob/master/doc/langdef.md#syntax) under `IDENT`.
1129+
This validity is checked at write time.
1130+
1131+
For per-policy runtime cost limit purposes, variables count towards the runtime cost limit
1132+
once per policy. The cost of each variable is computed when it is first evaluated in an
1133+
expression, mirroring how the cost limit would be calculated if the variable's
1134+
expression was embedded verbatim. If the runtime cost limit is exceeded in the
1135+
process, then evaluation halts. No individual variable or expression will be listed as the
1136+
cause in the resulting message. Whether or not the request actually fails depends on the failure policy,
1137+
however. For subsequent uses, inclusion of the variable has zero effect on the runtime
1138+
cost limit. If the variable evaluates to an array or some other iterable, and some expression
1139+
iterates on it, that of course contributes to the cost limit, but simply including the variable does
1140+
not add the underlying expression's cost again.
1141+
1142+
Variables are also subject to the per-expression runtime cost limit. Exceeding the per-expression
1143+
runtime cost limit is always attributed to the variable, unlike the per-policy limit.
1144+
1145+
Variables can only reference other variables that
1146+
have been previously defined in the `variables` section, so circular references
1147+
are not allowed.
1148+
1149+
If an error ocurrs during variable evaluation, then the expression
1150+
that caused it to be evaluated (since variable are always
1151+
lazily-evaluated) also finishes with an error. Evaluation for that
1152+
variable is not attempted again during the same validation; if any other
1153+
expressions attempt to evaluate a variable that already failed an evaluation
1154+
attempt, they will also be considered to have failed.
1155+
10951156
#### Secondary Authz
10961157

10971158
We will support admission control use cases requiring permission checks:

0 commit comments

Comments
 (0)