Skip to content

Commit c001f1c

Browse files
author
ymqytw
committed
reorder the proposals and update proposal
1 parent b33192d commit c001f1c

File tree

1 file changed

+113
-79
lines changed

1 file changed

+113
-79
lines changed

contributors/design-proposals/add-metadata-indicating-to-replace-union-in-patch.md contributors/design-proposals/support-union-in-api-server.md

+113-79
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,104 @@
1-
Add Tag Indicating To Replace *Union* Fields in Patch (a.k.a Support Replacing Maps in Strategic Merge Patch)
1+
Support Union in API Server
22
=============
33

4+
Generalize support for Unions in the API server. Instead of having the unionness of the field
5+
hard coded into the validation logic on a per-field basic, add first class support for validating unions.
6+
7+
## Proposed Changes
8+
9+
### APIs
10+
11+
**Scope**:
12+
13+
| Union Type | Supported |
14+
|---|---|
15+
| non-inlined non-discriminated union | Yes |
16+
| discriminated union | Yes |
17+
| inlined union with [patchMergeKey](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#strategic-merge-patch) only | Yes |
18+
| other inlined union | No |
19+
20+
Add a go struct tag / openAPI value indicating the field is a union and what type of union.
21+
22+
- Tag `union:"oneof"` means this is non-inlined non-discriminated union: only one of the fields in this struct can be set.
23+
24+
- Tag `union:"discriminator/<discriminatorName>"` means this field is a union with a discriminator in the struct.
25+
26+
- Tag `union: "inlined/<patchMergeKey>"` means this is an inlined union with only a `patchMergeKey`
27+
28+
Example of non-inlined non-discriminated union:
29+
```go
30+
type ContainerStatus struct {
31+
...
32+
// Add union: "oneof"
33+
State ContainerState `json:"state,omitempty" protobuf:"bytes,2,opt,name=state" union: "oneof"`
34+
...
35+
}
36+
```
37+
Example of discriminated union:
38+
```go
39+
type DeploymentSpec struct {
40+
...
41+
// Add union:"discriminator/type"
42+
Strategy DeploymentStrategy `json:"strategy,omitempty" protobuf:"bytes,4,opt,name=strategy" union:"discriminator/type"`
43+
...
44+
}
45+
```
46+
47+
Example of inlined union with `patchMergeKey` only:
48+
```go
49+
type PodSpec struct {
50+
...
51+
// Add union: "inlined/name"
52+
Volumes []Volume `json:"volumes,omitempty" patchStrategy:"merge" patchMergeKey:"name" union: "inlined/name" protobuf:"bytes,1,rep,name=volumes"`
53+
...
54+
}
55+
```
56+
57+
We don't make any changes on other inlined unions.
58+
59+
### Server Changes
60+
61+
- Validate that neither *PATCH* nor *UPDATE* set multiple values within a Union
62+
- Add first class support for validating discriminators if there are any.
63+
- *UPDATE* replaces the entire object, so there should be no need to clear anything in this case
64+
65+
For the inlined union that is not supported, we keep the validation code as it is.
66+
67+
### kubectl
68+
69+
When doing a *PATCH* to set one of the fields in a union, clear any other field in the union that
70+
was previously set. The client explicitly expresses setting one field and clearing the other fields.
71+
We provide the users a dry-run mode to let them check what is going to be sent to the server. E.g.
72+
```yaml
73+
containerstate:
74+
waiting:
75+
...
76+
running: null
77+
terminated: null
78+
```
79+
80+
### Open API change
81+
82+
We would need to add extensions to the openapi spec we publish. This is something we already need to do for the `patchStrategy` and `mergeKey` struct tags.
83+
84+
### Docs
85+
86+
Update `API-conventions-md` to include:
87+
```
88+
we should avoid adding new inlined unions in the future.
89+
```
90+
91+
## Summary
92+
93+
Limitation: We don't support inlined union types. Because the validator doesn't have
94+
enough metadata to distinguish the inlined union fields and other non-union fields.
95+
96+
# Alternatives Considered
97+
98+
The proposals below are not mutually exclusive with the proposal above, and maybe can be added at some point in the future.
99+
100+
# 1. Add Tag Indicating To Replace *Union* Fields in Patch (a.k.a Support Replacing Maps in Strategic Merge Patch)
101+
4102
This approach could be used to fix the issues with `kubectl apply` simply by having apply always replace union fields instead of patching them.
5103

6104
## Proposed Changes
@@ -81,7 +179,7 @@ No required change.
81179
82180
### Open API
83181
84-
We would need to add extensions to the openapi spec we publish. This is something we already need to do for the `patchStrategy` and `mergeKey` struct tags.
182+
Similar to section [Open API](#open-api-change)
85183
86184
### Strategic Merge Patch
87185
@@ -91,78 +189,14 @@ We need to add additional logic to support:
91189
- Generate the correct patch respecting the new tag, `patchStrategyForListEntry:"replace"`
92190
- Replace the entire union respecting the new directive, `$listEntryStrategy: replace`.
93191

94-
### Docs
95-
96-
Update `API-conventions-md` to include:
97-
```
98-
we should avoid adding new inlined unions in the future.
99-
```
100192

101193
## Summary
102-
Option 1: it may limit the flexibility to add more fields in the parent struct that already has an inlined union.
194+
Option 1: We lose the ability of *merging* the struct nested in the union field.
195+
And it may limit the flexibility to add more fields in the parent struct that already has an inlined union.
103196
**TODO**: we need to examine all the impacted APIs to check if it is safe to replace the entire parent struct.
104197

105198
Option 2: The limitation is that the metadata associated with the inlined APIs will not be reflected in the OpenAPI schema, because OpenAPI schemas flatten inlined structs.
106199

107-
# Alternatives Considered
108-
109-
The proposals below are not mutually exclusive with the proposal above, and maybe can be added at some point in the future.
110-
111-
# 1. Add Union Support to the API Server
112-
113-
## Proposed Changes
114-
115-
### APIs
116-
117-
Add a go struct tag / openAPI value telling the field is a union.
118-
119-
Tag `union:"oneof"` means only one of the fields in this struct can be set.
120-
121-
Tag `union:"discriminator"` means this field is a union with a discriminator in the struct. E.g. `union:"discriminator/type"` indicates the struct has a discriminator with name `type`.
122-
123-
Example of non-discriminated union:
124-
```go
125-
type ContainerStatus struct {
126-
...
127-
State ContainerState `json:"state,omitempty" protobuf:"bytes,2,opt,name=state" union: "oneof"`
128-
...
129-
}
130-
```
131-
Example of discriminated union:
132-
```go
133-
type DeploymentSpec struct {
134-
...
135-
Strategy DeploymentStrategy `json:"strategy,omitempty" protobuf:"bytes,4,opt,name=strategy" union:"discriminator/type"`
136-
...
137-
}
138-
```
139-
140-
### Server Changes
141-
142-
Generalize support for Unions in the server. Instead of having the union-ness of the field hard coded into the validation logic on a per-field basic, add first class support for validating unions.
143-
144-
- Validate that neither *PATCH* nor *UPDATE* set multiple values within a Union
145-
- *Maybe* add first class support for validating discriminators if there are any.
146-
- *UPDATE* replaces the entire object, so there should be no need to clear anything in this case
147-
148-
### kubectl
149-
150-
When doing a *PATCH* to set one of the fields in a union, clear any other field in the union that was previously set. The client explicitly expresses setting one field and clearing the other fields. We provide the users a dry-run mode to let them check what is going to be sent to the server. E.g.
151-
```yaml
152-
containerstate:
153-
waiting:
154-
reason: waitingReason
155-
message: watingMessage
156-
running: null
157-
terminated: null
158-
```
159-
160-
### Open API change
161-
162-
Similar to section [Open API](#open-api)
163-
164-
The limitation is that it will be very hard to make it work for inline union types. the validator doesn't have enough metadata to distinguish the inlined union fields and other non-union fields.
165-
166200
# 2. Add Discriminators in All Unions/OneOf APIs
167201

168202
Original issue is described in kubernetes/kubernetes#35345
@@ -200,15 +234,15 @@ No change required on kubectl.
200234

201235
## Summary
202236

203-
Limitation is that automatically clear fields based on discriminator may be unsafe.
237+
Limitation: Server-side automatically clearing fields based on discriminator may be unsafe.
204238

205239
# Appendix
206240

207241
## List of Impacted APIs
208242
In `pkg/api/v1/types.go`:
209-
- [`VolumeSource`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L235):
243+
- [`VolumeSource`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L235):
210244
It is inlined. Besides `VolumeSource`. its parent [Volume](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L222) has `Name`.
211-
- [`PersistentVolumeSource`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L345):
245+
- [`PersistentVolumeSource`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L345):
212246
It is inlined. Besides `PersistentVolumeSource`, its parent [PersistentVolumeSpec](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L442) has the following fields:
213247
```go
214248
Capacity ResourceList `json:"capacity,omitempty" protobuf:"bytes,1,rep,name=capacity,casttype=ResourceList,castkey=ResourceName"`
@@ -219,7 +253,7 @@ ClaimRef *ObjectReference `json:"claimRef,omitempty" protobuf:"bytes,4,opt,name=
219253
// +optional
220254
PersistentVolumeReclaimPolicy PersistentVolumeReclaimPolicy `json:"persistentVolumeReclaimPolicy,omitempty" protobuf:"bytes,5,opt,name=persistentVolumeReclaimPolicy,casttype=PersistentVolumeReclaimPolicy"`
221255
```
222-
- [`Handler`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L1485):
256+
- [`Handler`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L1485):
223257
It is inlined. Besides `Handler`, its parent struct [`Probe`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L1297) also has the following fields:
224258
```go
225259
// +optional
@@ -233,24 +267,24 @@ SuccessThreshold int32 `json:"successThreshold,omitempty" protobuf:"varint,5,opt
233267
// +optional
234268
FailureThreshold int32 `json:"failureThreshold,omitempty" protobuf:"varint,6,opt,name=failureThreshold"`
235269
````
236-
- [`ContainerState`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L1576):
270+
- [`ContainerState`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L1576):
237271
It is NOT inlined.
238272
- [`PodSignature`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/api/v1/types.go#L2953):
239273
It has only one field, but the comment says "Exactly one field should be set". Maybe we will add more in the future? It is NOT inlined.
240274
In `pkg/authorization/types.go`:
241-
- [`SubjectAccessReviewSpec`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/authorization/types.go#L108):
242-
Comments says: `Exactly one of ResourceAttributes and NonResourceAttributes must be set.`
275+
- [`SubjectAccessReviewSpec`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/authorization/types.go#L108):
276+
Comments says: `Exactly one of ResourceAttributes and NonResourceAttributes must be set.`
243277
But there are some other non-union fields in the struct.
244278
So this is similar to INLINED struct.
245-
- [`SelfSubjectAccessReviewSpec`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/authorization/types.go#L130):
279+
- [`SelfSubjectAccessReviewSpec`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/authorization/types.go#L130):
246280
It is NOT inlined.
247281

248282
In `pkg/apis/extensions/v1beta1/types.go`:
249-
- [`DeploymentStrategy`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/types.go#L249):
283+
- [`DeploymentStrategy`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/types.go#L249):
250284
It is NOT inlined.
251-
- [`NetworkPolicyPeer`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/v1beta1/types.go#L1340):
285+
- [`NetworkPolicyPeer`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/v1beta1/types.go#L1340):
252286
It is NOT inlined.
253-
- [`IngressRuleValue`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/v1beta1/types.go#L876):
287+
- [`IngressRuleValue`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/v1beta1/types.go#L876):
254288
It says "exactly one of the following must be set". But it has only one field.
255289
It is inlined. Its parent [`IngressRule`](https://github.com/kubernetes/kubernetes/blob/v1.5.2/pkg/apis/extensions/v1beta1/types.go#L848) also has the following fields:
256290
```go

0 commit comments

Comments
 (0)