commit
f11408f7d6
|
@ -26,11 +26,6 @@ An introduction to using resources with kubectl can be found in [the object mana
|
||||||
- [Verbs on Resources](#verbs-on-resources)
|
- [Verbs on Resources](#verbs-on-resources)
|
||||||
- [PATCH operations](#patch-operations)
|
- [PATCH operations](#patch-operations)
|
||||||
- [Strategic Merge Patch](#strategic-merge-patch)
|
- [Strategic Merge Patch](#strategic-merge-patch)
|
||||||
- [List Operations](#list-operations)
|
|
||||||
- [List of Maps](#list-of-maps)
|
|
||||||
- [List of Primitives](#list-of-primitives)
|
|
||||||
- [Unordered Set](#unordered-set)
|
|
||||||
- [Map Operations](#map-operations)
|
|
||||||
- [Idempotency](#idempotency)
|
- [Idempotency](#idempotency)
|
||||||
- [Optional vs. Required](#optional-vs-required)
|
- [Optional vs. Required](#optional-vs-required)
|
||||||
- [Defaulting](#defaulting)
|
- [Defaulting](#defaulting)
|
||||||
|
@ -555,172 +550,7 @@ below.
|
||||||
|
|
||||||
#### Strategic Merge Patch
|
#### Strategic Merge Patch
|
||||||
|
|
||||||
In the standard JSON merge patch, JSON objects are always merged but lists are
|
Details of Strategic Merge Patch are covered [here](../strategic-merge-patch.md).
|
||||||
always replaced. Often that isn't what we want. Let's say we start with the
|
|
||||||
following Pod:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx-1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
...and we POST that to the server (as JSON). Then let's say we want to *add* a
|
|
||||||
container to this Pod.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
PATCH /api/v1/namespaces/default/pods/pod-name
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: log-tailer
|
|
||||||
image: log-tailer-1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
If we were to use standard Merge Patch, the entire container list would be
|
|
||||||
replaced with the single log-tailer container. However, our intent is for the
|
|
||||||
container lists to merge together based on the `name` field.
|
|
||||||
|
|
||||||
To solve this problem, Strategic Merge Patch uses the go struct tag of the API
|
|
||||||
objects to determine what lists should be merged and which ones should not.
|
|
||||||
Currently the metadata is available as struct tags on the API objects
|
|
||||||
themselves, but will become available to clients as Swagger annotations in the
|
|
||||||
future. In the above example, the `patchStrategy` metadata for the `containers`
|
|
||||||
field would be `merge` and the `patchMergeKey` would be `name`.
|
|
||||||
|
|
||||||
Note: If the patch results in merging two lists of primitives, the primitives are
|
|
||||||
first deduplicated and then merged.
|
|
||||||
|
|
||||||
Strategic Merge Patch also supports special operations as listed below.
|
|
||||||
|
|
||||||
### List Operations
|
|
||||||
|
|
||||||
#### List of Maps
|
|
||||||
|
|
||||||
To override the container list to be strictly replaced, regardless of the
|
|
||||||
default:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx-1.0
|
|
||||||
- $patch: replace # any further $patch operations nested in this list will be ignored
|
|
||||||
```
|
|
||||||
|
|
||||||
To delete an element of a list that should be merged:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx-1.0
|
|
||||||
- $patch: delete
|
|
||||||
name: log-tailer # merge key and value goes here
|
|
||||||
```
|
|
||||||
|
|
||||||
Delete operation will delete the first entry in the list that match the merge key.
|
|
||||||
But there is validation to make sure no 2 entries with the same merge key will get in the list.
|
|
||||||
|
|
||||||
#### List of Primitives
|
|
||||||
|
|
||||||
We have two patch strategies for lists of primitives: replace and merge.
|
|
||||||
Replace is the default patch strategy, which will replace the whole list on update and it will preserve the order;
|
|
||||||
while merge strategy works as an unordered set. In this section, we call a primitive list with merge strategy an unordered set.
|
|
||||||
The patch strategy is defined in the go struct tag of the API objects,
|
|
||||||
e.g. `finalizers` uses `merge` as patch strategy.
|
|
||||||
```go
|
|
||||||
Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Unordered Set
|
|
||||||
|
|
||||||
There are 3 operations: add, delete, replace.
|
|
||||||
|
|
||||||
Suppose we have defined a `finalizers` and we call it the original finalizers:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
finalizers:
|
|
||||||
- a
|
|
||||||
- b
|
|
||||||
- c
|
|
||||||
```
|
|
||||||
|
|
||||||
1) To add items in a set, we use the list name as the key.
|
|
||||||
e.g. to add items "d" and "e" in the original finalizers, the patch will be:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
finalizers:
|
|
||||||
- d
|
|
||||||
- e
|
|
||||||
```
|
|
||||||
|
|
||||||
After applying the patch on the original finalizers, it will become:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
finalizers:
|
|
||||||
- a
|
|
||||||
- b
|
|
||||||
- c
|
|
||||||
- d
|
|
||||||
- e
|
|
||||||
```
|
|
||||||
|
|
||||||
2) To delete items in a set, we use a parallel list with key: `$deleteFromPrimitiveList/\<keyOfPrimitiveList\>`.
|
|
||||||
e.g. to delete items "b" and "c" from the original finalizers, the patch will be:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
$deleteFromPrimitiveList/finalizers:
|
|
||||||
- b
|
|
||||||
- c
|
|
||||||
```
|
|
||||||
|
|
||||||
After applying the patch on the original finalizers, it will become:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
finalizers:
|
|
||||||
- a
|
|
||||||
```
|
|
||||||
|
|
||||||
In an erroneous case, the set may be created with duplicates. Deleting an item that has duplicates will delete all matching items.
|
|
||||||
|
|
||||||
3) Replace can be fulfilled by an addition and a deletion.
|
|
||||||
e.g. to replace "a" with "x" in the original finalizers, the patch will be:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
$deleteFromPrimitiveList/finalizers:
|
|
||||||
- a
|
|
||||||
finalizers:
|
|
||||||
- x
|
|
||||||
```
|
|
||||||
|
|
||||||
After applying the patch on the original finalizers, it will become:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
finalizers:
|
|
||||||
- x
|
|
||||||
- b
|
|
||||||
- c
|
|
||||||
```
|
|
||||||
|
|
||||||
### Map Operations
|
|
||||||
|
|
||||||
To indicate that a map should not be merged and instead should be taken literally:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
$patch: replace # recursive and applies to all fields of the map it's in
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx-1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
To delete a field of a map:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: nginx
|
|
||||||
image: nginx-1.0
|
|
||||||
labels:
|
|
||||||
live: null # set the value of the map key to null
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Idempotency
|
## Idempotency
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
Strategic Merge Patch
|
||||||
|
=====================
|
||||||
|
|
||||||
|
# Background
|
||||||
|
|
||||||
|
TODO: @pwittrock complete this section
|
||||||
|
|
||||||
|
In the standard JSON merge patch, JSON objects are always merged but lists are
|
||||||
|
always replaced. Often that isn't what we want. Let's say we start with the
|
||||||
|
following Pod:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx-1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
and we POST that to the server (as JSON). Then let's say we want to *add* a
|
||||||
|
container to this Pod.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
PATCH /api/v1/namespaces/default/pods/pod-name
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: log-tailer
|
||||||
|
image: log-tailer-1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
If we were to use standard Merge Patch, the entire container list would be
|
||||||
|
replaced with the single log-tailer container. However, our intent is for the
|
||||||
|
container lists to merge together based on the `name` field.
|
||||||
|
|
||||||
|
To solve this problem, Strategic Merge Patch uses the go struct tag of the API
|
||||||
|
objects to determine what lists should be merged and which ones should not.
|
||||||
|
Currently the metadata is available as struct tags on the API objects
|
||||||
|
themselves, but will become available to clients as Swagger annotations in the
|
||||||
|
future. In the above example, the `patchStrategy` metadata for the `containers`
|
||||||
|
field would be `merge` and the `patchMergeKey` would be `name`.
|
||||||
|
|
||||||
|
|
||||||
|
# Basic Patch Format
|
||||||
|
|
||||||
|
Strategic Merge Patch supports special operations through directives.
|
||||||
|
|
||||||
|
There are multiple directives:
|
||||||
|
|
||||||
|
- replace
|
||||||
|
- merge
|
||||||
|
- delete
|
||||||
|
- delete from primitive list
|
||||||
|
|
||||||
|
`replace`, `merge` and `delete` are mutual exclusive.
|
||||||
|
|
||||||
|
## `replace` Directive
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
|
||||||
|
`replace` directive indicates that the element that contains it should be replaced instead of being merged.
|
||||||
|
|
||||||
|
### Syntax
|
||||||
|
|
||||||
|
`replace` directive is used in both patch with directive marker and go struct tags.
|
||||||
|
|
||||||
|
Example usage in the patch:
|
||||||
|
|
||||||
|
```
|
||||||
|
$patch: replace
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
`replace` directive can be used on both map and list.
|
||||||
|
|
||||||
|
#### Map
|
||||||
|
|
||||||
|
To indicate that a map should not be merged and instead should be taken literally:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
$patch: replace # recursive and applies to all fields of the map it's in
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx-1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### List of Maps
|
||||||
|
|
||||||
|
To override the container list to be strictly replaced, regardless of the default:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx-1.0
|
||||||
|
- $patch: replace # any further $patch operations nested in this list will be ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## `delete` Directive
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
|
||||||
|
`delete` directive indicates that the element that contains it should be deleted.
|
||||||
|
|
||||||
|
### Syntax
|
||||||
|
|
||||||
|
`delete` directive is used only in the patch with directive marker.
|
||||||
|
It can be used on both map and list of maps.
|
||||||
|
```
|
||||||
|
$patch: delete
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
#### List of Maps
|
||||||
|
|
||||||
|
To delete an element of a list that should be merged:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: nginx-1.0
|
||||||
|
- $patch: delete
|
||||||
|
name: log-tailer # merge key and value goes here
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Delete operation will delete all entries in the list that match the merge key.
|
||||||
|
|
||||||
|
#### Maps
|
||||||
|
|
||||||
|
One way to delete a map is using `delete` directive.
|
||||||
|
Applying this patch will delete the rollingUpdate map.
|
||||||
|
```yaml
|
||||||
|
rollingUpdate:
|
||||||
|
$patch: delete
|
||||||
|
```
|
||||||
|
|
||||||
|
An equivalent way to delete this map is
|
||||||
|
```yaml
|
||||||
|
rollingUpdate: null
|
||||||
|
```
|
||||||
|
|
||||||
|
## `merge` Directive
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
|
||||||
|
`merge` directive indicates that the element that contains it should be merged instead of being replaced.
|
||||||
|
|
||||||
|
### Syntax
|
||||||
|
|
||||||
|
`merge` directive is used only in the go struct tags.
|
||||||
|
|
||||||
|
|
||||||
|
## `deleteFromPrimitiveList` Directive
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
|
||||||
|
We have two patch strategies for lists of primitives: replace and merge.
|
||||||
|
Replace is the default patch strategy for list, which will replace the whole list on update and it will preserve the order;
|
||||||
|
while merge strategy works as an unordered set. We call a primitive list with merge strategy an unordered set.
|
||||||
|
The patch strategy is defined in the go struct tag of the API objects.
|
||||||
|
|
||||||
|
`deleteFromPrimitiveList` directive indicates that the elements in this list should be deleted from the original primitive list.
|
||||||
|
|
||||||
|
### Syntax
|
||||||
|
|
||||||
|
It is used only as the prefix of the key in the patch.
|
||||||
|
```
|
||||||
|
$deleteFromPrimitiveList/<keyOfPrimitiveList>: [a primitive list]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
##### List of Primitives (Unordered Set)
|
||||||
|
|
||||||
|
`finalizers` uses `merge` as patch strategy.
|
||||||
|
```go
|
||||||
|
Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppose we have defined a `finalizers` and we call it the original finalizers:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
finalizers:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete items "b" and "c" from the original finalizers, the patch will be:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# The directive includes the prefix $deleteFromPrimitiveList and
|
||||||
|
# followed by a '/' and the name of the list.
|
||||||
|
# The values in this list will be deleted after applying the patch.
|
||||||
|
$deleteFromPrimitiveList/finalizers:
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
```
|
||||||
|
|
||||||
|
After applying the patch on the original finalizers, it will become:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
finalizers:
|
||||||
|
- a
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: When merging two set, the primitives are first deduplicated and then merged.
|
||||||
|
In an erroneous case, the set may be created with duplicates. Deleting an
|
||||||
|
item that has duplicates will delete all matching items.
|
||||||
|
|
||||||
|
|
||||||
|
TODO: @pwittrock
|
||||||
|
# Changing Patch Format
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
## Requirement
|
||||||
|
|
||||||
|
### Version Skew
|
||||||
|
|
||||||
|
## Strategy
|
||||||
|
|
||||||
|
## Example
|
Loading…
Reference in New Issue