Address comments

This commit is contained in:
cici37
2022-04-06 16:08:12 -07:00
parent e638ab5ee8
commit 40157c8e05
@@ -716,7 +716,7 @@ CustomResourceDefinition schemas using the `x-kubernetes-validations` extension.
The Rule is scoped to the location of the `x-kubernetes-validations` extension in the schema.
And `self` variable in the CEL expression is bound to the scoped value.
Note all the validation rules are scoped to the current object, no cross-object or stateful validation rules are supported.
All validation rules are scoped to the current object: no cross-object or stateful validation rules are supported.
For example:
@@ -996,18 +996,18 @@ Here is the declarations type mapping between OpenAPIv3 and CEL type:
xref: [CEL types](https://github.com/google/cel-spec/blob/v0.6.0/doc/langdef.md#values), [OpenAPI
types](https://swagger.io/specification/#data-types), [Kubernetes Structural Schemas](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema).
#### Function Library
#### Validation functions {#available-validation-functions}
Functions available include:
- CEL standard functions, defined in the[list of standard definitions](https://github.com/google/cel-spec/blob/v0.7.0/doc/langdef.md#list-of-standard-definitions)
- CEL standard functions, defined in the [list of standard definitions](https://github.com/google/cel-spec/blob/v0.7.0/doc/langdef.md#list-of-standard-definitions)
- CEL standard [macros](https://github.com/google/cel-spec/blob/v0.7.0/doc/langdef.md#macros)
- CEL [extended string function library](https://pkg.go.dev/github.com/google/cel-go@v0.11.2/ext#Strings)
- Kubernetes [CEL extension library](https://pkg.go.dev/k8s.io/apiextensions-apiserver@v0.24.0-alpha.4/pkg/apiserver/schema/cel/library#pkg-functions)
- Kubernetes [CEL extension library](https://pkg.go.dev/k8s.io/apiextensions-apiserver@v0.24.0/pkg/apiserver/schema/cel/library#pkg-functions)
#### Transition Rules
#### Transition rules
A rule that contains an expression referencing the identifier `oldSelf` is implicitly considered a
"transition rule". Transition rules allow schema authors to prevent certain transitions between two
_transition rule_. Transition rules allow schema authors to prevent certain transitions between two
otherwise valid states. For example:
```yaml
@@ -1036,33 +1036,40 @@ Errors will be generated on CRD writes if a schema node contains a transition ru
applied, e.g. "*path*: update rule *rule* cannot be set on schema because the schema or its parent
schema is not mergeable".
Transition rules are only allowed on "correlatable" portions of a schema.
Transition rules are only allowed on _correlatable portions_ of a schema.
A portion of the schema is correlatable if all `array` parent schemas are of type `x-kubernetes-list-type=map`; any `set`or `atomic`array parent schemas make it impossible to unambiguously correlate a `self` with `oldSelf`.
##### Use Cases
Here are some examples for transition rules:
{{< table caption="Transition rules examples" >}}
| Use Case | Rule
| -------- | --------
| Immutability | `self.foo == oldSelf.foo`
| Prevent modification/removal once assigned | `oldSelf != 'bar' \|\| self == 'bar'` or `!has(oldSelf.field) \|\| has(self.field)`
| Append-only set | `self.all(element, element in oldSelf)`
| If previous value was X, new value can only be A or B, not Y or Z | `oldSelf != 'X' \|\| self in ['A', 'B']`
| Nondecreasing counters | `self >= oldSelf`
| Monotonic (non-decreasing) counters | `self >= oldSelf`
{{< /table >}}
#### Resource Constraints
#### Resource use by validation functions
Resource consumption of validation rules is checked at CustomResourceDefinition creation and update time. If a rule is estimated to be prohibitively expensive to execute, it will result in a validation error. A similar
system is used at runtime that observes the actions the interpreter takes. If the interpreter executes
When you create or update a CustomResourceDefinition that uses validation rules,
the API server checks the likely impact of running those validation rules. If a rule is
estimated to be prohibitively expensive to execute, the API server rejects the create
or update operation, and returns an error message.
A similar system is used at runtime that observes the actions the interpreter takes. If the interpreter executes
too many instructions, execution of the rule will be halted, and an error will result.
Each CustomResourceDefinition is also allowed a certain amount of resources to finish executing all of
its validation rules. If the sum total of its rules are estimated at creation time to go over that limit,
then a validation error will also occur.
In general, both systems will allow rules that do not need to iterate; these rules will
always take the same amount of time regardless of how large their input is. `self.foo == 1` will be allowed.
But if `foo` is a string and we instead have `self.foo.contains("someString")`, our rule will take
longer to execute depending on how long `foo` is. Another example would be if `foo` was an array, and we
had a rule `self.foo.all(x, x > 5)`. The cost system will always assume the worst-case scenario if
You are unlikely to encounter issues with the resource budget for validation if you only
specify rules that always take the same amount of time regardless of how large their input is.
For example, a rule that asserts that `self.foo == 1` does not by itself have any
risk of rejection on validation resource budget groups.
But if `foo` is a string and you define a validation rule `self.foo.contains("someString")`, that rule takes
longer to execute depending on how long `foo` is.
Another example would be if `foo` were an array, and you specified a validation rule `self.foo.all(x, x > 5)`. The cost system always assumes the worst-case scenario if
a limit on the length of `foo` is not given, and this will happen for anything that can be iterated
over (lists, maps, etc.).
@@ -1081,17 +1088,18 @@ openAPIV3Schema:
- rule: "self.all(x, x.contains('a string'))"
```
The cost system will not allow this rule. Using `self.all` means calling `contains` on every string in `foo`,
which in turn will check the given string to see if it contains `'a string'`. Without limits, this is a very
expensive rule:
then the API server rejects this rule on validation budget grounds with error:
```
spec.validation.openAPIV3Schema.properties[spec].properties[foo].x-kubernetes-validations[0].rule: Forbidden:
CEL rule exceeded budget by more than 100x (try simplifying the rule, or adding maxItems, maxProperties, and
maxLength where arrays, maps, and strings are used)
```
Without limits being set, the estimated cost of this rule will exceed the per-rule cost limit. But if we
The rejection happens because `self.all` implies calling `contains()` on every string in `foo`,
which in turn will check the given string to see if it contains `'a string'`. Without limits, this is a very
expensive rule.
If you do not specify any validation limit, the estimated cost of this rule will exceed the per-rule cost limit. But if you
add limits in the appropriate places, the rule will be allowed:
```yaml