|
55 | 55 | - [Difficulties with <code>+k8s:required</code> and <code>+k8s:default</code>](#difficulties-with-k8srequired-and-k8sdefault)
|
56 | 56 | - [Proposed Solutions](#proposed-solutions)
|
57 | 57 | - [Addressing the Problem with Valid Zero Values Using the Linter](#addressing-the-problem-with-valid-zero-values-using-the-linter)
|
| 58 | + - [Subresources](#subresources) |
| 59 | + - [Status-Type Subresources](#status-type-subresources) |
| 60 | + - [Scale-Type Subresources](#scale-type-subresources) |
| 61 | + - [Streaming Subresources](#streaming-subresources) |
58 | 62 | - [Ratcheting](#ratcheting)
|
59 | 63 | - [Test Plan](#test-plan)
|
60 | 64 | - [Prerequisite testing updates](#prerequisite-testing-updates)
|
@@ -946,71 +950,68 @@ The linter will flag any violations of these rules, ensuring consistent zero-val
|
946 | 950 |
|
947 | 951 | ### Subresources
|
948 | 952 |
|
949 |
| -#### Status style subresources |
| 953 | +#### Status-Type Subresources |
950 | 954 |
|
951 |
| -These are subresources that: |
| 955 | +These subresources have the following characteristics: |
952 | 956 |
|
953 |
| -- Share the root resource. (Same Kind, same storage object). |
954 |
| -- Typically, have constraints on which fields may be updated. |
955 |
| -- In some cases, may allow updates not otherwise allowed. |
| 957 | +* They operate on the same underlying storage object as the primary resource (i.e., same `kind`, same object in etcd). |
| 958 | +* Updates via these subresources are typically constrained to specific fields within the object. |
| 959 | +* In some cases, they permit writes to fields normally disallowed via the primary resource. |
956 | 960 |
|
957 |
| -Examples: |
| 961 | +**Examples:** |
958 | 962 |
|
959 |
| - - `pods/status` may update to the `metadata` and `status` stanzas, but not the `spec` stanza. |
960 |
| - - `resourceclaims/status` may only update the `status` stanza, but not the `metadata` or `spec` stanza. |
961 |
| - - `pods/resize` may update `spec.container[*].resources` fields, which are immutable via the root `pods` resource. |
962 |
| - - `certificatesigningrequests/approval` may add/remove/modify the Approved/Denied status conditions. |
| 963 | +* `pods/status`: Allows updates only to the `metadata` and `status` stanzas, prohibiting changes to the `spec`. |
| 964 | +* `resourceclaims/status`: Allows updates only to the `status` stanza, prohibiting changes to `metadata` or `spec`. |
| 965 | +* `pods/resize`: Allows updates to `spec.container[*].resources` fields, which are normally immutable after Pod creation via the primary `pods` resource. |
| 966 | +* `certificatesigningrequests/approval`: Allows adding, removing, or modifying Approve/Deny conditions within the `status`. |
963 | 967 |
|
964 |
| -To validate these fields, Declarative Validation will: |
| 968 | +**Validation Process for Status-Type Subresources:** |
965 | 969 |
|
966 |
| -- Does NOT constraint which fields a subresource operation is allowed to write. This will |
967 |
| - responsibility of "field wiping". Field wiping logic is expected to be handled in resource |
968 |
| - strategies by modifying (wiping) the incoming object before it is validated. |
969 |
| -- Validates the entire resource using same declarative validation as used to validate the root |
970 |
| - resource. But, allows validation tags to perform conditional validation based on the subresource. |
971 |
| -- Uses ratcheting to skip validation of unchanged fields. Combined with field wiping, this |
972 |
| - isolates the actual validation performed to the subset of fields that are allowed to be updated |
973 |
| - via the subresource. |
| 970 | +Declarative Validation handles these as follows: |
974 | 971 |
|
975 |
| -Examples: |
| 972 | +1. **Field Wiping (Pre-Validation):** Declarative Validation *does not* constrain which fields a subresource operation can write. Instead, this responsibility lies with the resource's strategy implementation. The strategy modifies the incoming object *before* validation, effectively "wiping" or resetting any fields the specific subresource operation is not allowed to change. |
| 973 | +2. **Full Resource Validation:** The *entire*, modified resource object is then validated using the *same* set of declarative validation rules applied to the primary resource. |
| 974 | +3. **Conditional Validation:** Validation rules can use a special `subresources` parameter (e.g., `subresources == ['status']`) to apply conditional logic. This allows rules to behave differently depending on whether the update comes via the primary resource or a specific subresource. |
| 975 | +4. **Ratcheting:** Declarative Validation uses ratcheting, meaning it skips validation checks on fields that have not changed from the existing stored object. Combined with field wiping, this effectively isolates the validation to only the subset of fields that the subresource operation is intended and permitted to modify. |
976 | 976 |
|
977 |
| - - `pods/status` will be validated with the same declarative validation tags as the root `pods` resource after field wiping has been applied to the `spec`. |
978 |
| - - `pods/resize` will be validated with the same declarative validation tags as the root `pods`, but the root resource validation will consult the |
979 |
| - subresource parameter when validating `spec.container[*].resources` to ensure immutability unless updated via the `pods/resize` subresource via |
980 |
| - a rule such as: `+k8s:if('subresources != ["resize"]')=+k8s:immutable` |
| 977 | +**Validation Examples:** |
981 | 978 |
|
982 |
| -To support these types of subresources, declarative validation will be extended to: |
| 979 | +* An update via `pods/status` first has its `spec` field changes wiped by the Pod strategy. Then, the entire Pod object is validated using the standard Pod validation rules. Ratcheting skips checks on unchanged `metadata` or `status` fields. |
| 980 | +* An update via `pods/resize` is validated using the standard Pod rules. However, a rule on `spec.container[*].resources` might look like `+k8s:if('subresources != ["resize"]')=+k8s:immutable`, effectively enforcing immutability *unless* the update comes via the `resize` subresource. |
983 | 981 |
|
984 |
| -- Provide a "subresources" parameter that is accessible via validation tags so that conditional validation is possible. |
| 982 | +**Support required:** |
985 | 983 |
|
986 |
| -#### Scale style subresources |
| 984 | +* To enable conditional validation, declarative validation provides access to the `subresources` parameter within validation rule expressions. |
987 | 985 |
|
988 |
| -These are subresources that: |
| 986 | +#### Scale-Type Subresources |
989 | 987 |
|
990 |
| -- Have a different Kind than the root resource. |
991 |
| -- Share the storage object of the root resource. (updates to the subresource fields result in writes to corresponding stored to fields of the root resource). |
| 988 | +These subresources have the following characteristics: |
992 | 989 |
|
993 |
| -Examples: |
| 990 | +* They often represent a different API `kind` (e.g., `autoscaling/v1.Scale`) than the resource they modify (e.g., `apps/v1.Deployment`). |
| 991 | +* Despite being a different `kind`, updates to the subresource modify fields within the underlying storage object of the *primary* resource. |
994 | 992 |
|
995 |
| -- Update to `pods/scale` may modify `spec.replicas` to cause an update to the `spec.replicas` field of the root `pods` resource. |
996 |
| -- Create of `pods/binding` provides a `target` to cause the `pod.spec.nodeName` to be set on the root `pods` resource (but only if nodeName is not already set). |
| 993 | +**Examples:** |
997 | 994 |
|
998 |
| -To validate these fields, Declarative Validation will (in the storage layer of an API definition): |
| 995 | +* An update to `deployments/scale` modifies the `spec.replicas` field within the stored `Deployment` object. |
| 996 | +* Creating a `Binding` object via `pods/binding` sets the `spec.nodeName` field on the target `Pod` object. |
999 | 997 |
|
1000 |
| -- Validates the subresource declaratively. |
1001 |
| -- Relies on the resource's storage layer to apply the write to the root resource. |
1002 |
| -- Validates the root resource normally. |
1003 |
| -- Uses ratcheting to skip validation of unchanged fields. |
| 998 | +**Validation Process for Scale-Type Subresources:** |
1004 | 999 |
|
1005 |
| -To support these types of subresources, declarative validation will be extended to: |
| 1000 | +Declarative Validation involves multiple steps, coordinated with the storage layer: |
1006 | 1001 |
|
1007 |
| -- Accept the mapping from internal type to versioned type of scale style subresources so that a `ValidateDeclaratively(..., internal.Scale, ...)` request |
1008 |
| - is mapped to the same Scale group/version as the request (for example, `autoscaling.k8s.io/v1`) and then validated. |
1009 |
| -- https://github.com/jpbetz/kubernetes/pull/141 provides an example of how to migrate a resource to scale subresource declarative validation. |
| 1002 | +1. **Subresource Validation:** The incoming subresource object itself (e.g., the `autoscaling/v1.Scale` object) is validated using *its own* declarative rules. |
| 1003 | +2. **Storage Layer Application:** The resource's storage layer logic translates the validated subresource update into changes on the primary resource's fields (e.g., mapping the `Scale` object's `spec.replicas` to the `Deployment` object's `spec.replicas`). |
| 1004 | +3. **Primary Resource Validation:** The *modified primary resource* (e.g., `Deployment`) is then validated using *its* standard declarative validation rules. |
| 1005 | +4. **Ratcheting:** Ratcheting is applied during the primary resource validation, skipping checks on fields that were not affected by the scale operation. |
1010 | 1006 |
|
1011 |
| -#### Streaming subresources |
| 1007 | +**Support required:** |
1012 | 1008 |
|
1013 |
| -Streaming endpoints such as `pod/exec`, `pod/attach` and `pod/portForward` are not validated normally and will not be migrated to declarative validation. |
| 1009 | +* The declarative validation framework needs a mapping from the internal Go type representation of the scale subresource to its versioned API type (e.g., mapping `internal.Scale` to `autoscaling.k8s.io/v1.Scale`). This allow the `ValidateDeclaratively(..., internal.Scale, ...)` call from the storage layer to correctly find and apply the validation rules for the specific GVK (`autoscaling/v1.Scale`) associated with the requested subresource. |
| 1010 | +* Refer to https://github.com/jpbetz/kubernetes/pull/141 for an example of migrating a `/scale` subresource. |
| 1011 | + |
| 1012 | +#### Streaming Subresources |
| 1013 | + |
| 1014 | +Subresources such as `pods/exec`, `pods/attach`, and `pods/portforward` do not require declarative validation, as they operate on data streams, not structured resource data. |
1014 | 1015 |
|
1015 | 1016 | ### Ratcheting
|
1016 | 1017 |
|
|
0 commit comments