Skip to content

Commit

Permalink
Merge pull request #40666 from ymqytw/support_generic_merge_patch
Browse files Browse the repository at this point in the history
Automatic merge from submit-queue (batch tested with PRs 40864, 40666, 38382, 40874)

apply falls back to generic JSON patch computation if no go struct is registered for the target GVK

This PR is the master version of #40096 which is target 1.4 branch.
This PR is based on #40260 

- [x] ensure subkey deletion works in CreateThreeWayJSONMergePatch
- [x] ensure type stomping works in CreateThreeWayJSONMergePatch
- [x] lots of tests for generic json patch computation
- [x] apply falls back to generic 3-way JSON merge patch if no go struct is registered for the target GVK
  - [x] prevent generic apply patch computation between different apiVersions and/or kinds
  - [x] make pruner generic (apply --prune works with TPR)

```release-note
apply falls back to generic 3-way JSON merge patch if no go struct is registered for the target GVK
```
  • Loading branch information
Kubernetes Submit Queue committed Feb 3, 2017
2 parents 1fab123 + 710d904 commit 99def0d
Show file tree
Hide file tree
Showing 17 changed files with 1,164 additions and 72 deletions.
162 changes: 136 additions & 26 deletions hack/make-rules/test-cmd-util.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1259,17 +1259,7 @@ __EOF__
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

# Test that we can create a new resource of type Foo
kubectl "${kube_flags[@]}" create -f - "${kube_flags[@]}" << __EOF__
{
"kind": "Foo",
"apiVersion": "company.com/v1",
"metadata": {
"name": "test"
},
"some-field": "field1",
"other-field": "field2"
}
__EOF__
kubectl "${kube_flags[@]}" create -f hack/testdata/TPR/foo.yaml "${kube_flags[@]}"

# Test that we can list this new third party resource
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" 'test:'
Expand All @@ -1291,10 +1281,10 @@ __EOF__
kubectl "${kube_flags[@]}" get foos/test -o json
kubectl "${kube_flags[@]}" get foos -o yaml
kubectl "${kube_flags[@]}" get foos/test -o yaml
kubectl "${kube_flags[@]}" get foos -o "jsonpath={.items[*].some-field}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos/test -o "jsonpath={.some-field}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos -o "go-template={{range .items}}{{index . \"some-field\"}}{{end}}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos/test -o "go-template={{index . \"some-field\"}}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos -o "jsonpath={.items[*].someField}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos/test -o "jsonpath={.someField}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos -o "go-template={{range .items}}{{.someField}}{{end}}" --allow-missing-template-keys=false
kubectl "${kube_flags[@]}" get foos/test -o "go-template={{.someField}}" --allow-missing-template-keys=false

# Test patching
kube::log::status "Testing ThirdPartyResource patching"
Expand Down Expand Up @@ -1348,17 +1338,7 @@ __EOF__
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''

# Test that we can create a new resource of type Bar
kubectl "${kube_flags[@]}" create -f - "${kube_flags[@]}" << __EOF__
{
"kind": "Bar",
"apiVersion": "company.com/v1",
"metadata": {
"name": "test"
},
"some-field": "field1",
"other-field": "field2"
}
__EOF__
kubectl "${kube_flags[@]}" create -f hack/testdata/TPR/bar.yaml "${kube_flags[@]}"

# Test that we can list this new third party resource
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" 'test:'
Expand All @@ -1369,6 +1349,136 @@ __EOF__
# Make sure it's gone
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

# Test that we can create single item via apply
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/foo.yaml

# Test that we have create a foo named test
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" 'test:'

# Test that the field has the expected value
kube::test::get_object_assert foos/test '{{.someField}}' 'field1'

# Test that apply an empty patch doesn't change fields
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/foo.yaml

# Test that the field has the same value after re-apply
kube::test::get_object_assert foos/test '{{.someField}}' 'field1'

# Test that apply has updated the subfield
kube::test::get_object_assert foos/test '{{.nestedField.someSubfield}}' 'subfield1'

# Update a subfield and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/foo-updated-subfield.yaml

# Test that apply has updated the subfield
kube::test::get_object_assert foos/test '{{.nestedField.someSubfield}}' 'modifiedSubfield'

# Test that the field has the expected value
kube::test::get_object_assert foos/test '{{.nestedField.otherSubfield}}' 'subfield2'

# Delete a subfield and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/foo-deleted-subfield.yaml

# Test that apply has deleted the field
kube::test::get_object_assert foos/test '{{.nestedField.otherSubfield}}' '<no value>'

# Test that the field does not exist
kube::test::get_object_assert foos/test '{{.nestedField.newSubfield}}' '<no value>'

# Add a field and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/foo-added-subfield.yaml

# Test that apply has added the field
kube::test::get_object_assert foos/test '{{.nestedField.newSubfield}}' 'subfield3'

# Delete the resource
kubectl "${kube_flags[@]}" delete -f hack/testdata/TPR/foo.yaml

# Make sure it's gone
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''

# Test that we can create list via apply
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/multi-tpr-list.yaml

# Test that we have create a foo and a bar from a list
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" 'test-list:'
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" 'test-list:'

# Test that the field has the expected value
kube::test::get_object_assert foos/test-list '{{.someField}}' 'field1'
kube::test::get_object_assert bars/test-list '{{.someField}}' 'field1'

# Test that re-apply an list doesn't change anything
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/multi-tpr-list.yaml

# Test that the field has the same value after re-apply
kube::test::get_object_assert foos/test-list '{{.someField}}' 'field1'
kube::test::get_object_assert bars/test-list '{{.someField}}' 'field1'

# Test that the fields have the expected value
kube::test::get_object_assert foos/test-list '{{.someField}}' 'field1'
kube::test::get_object_assert bars/test-list '{{.someField}}' 'field1'

# Update fields and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/multi-tpr-list-updated-field.yaml

# Test that apply has updated the fields
kube::test::get_object_assert foos/test-list '{{.someField}}' 'modifiedField'
kube::test::get_object_assert bars/test-list '{{.someField}}' 'modifiedField'

# Test that the field has the expected value
kube::test::get_object_assert foos/test-list '{{.otherField}}' 'field2'
kube::test::get_object_assert bars/test-list '{{.otherField}}' 'field2'

# Delete fields and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/multi-tpr-list-deleted-field.yaml

# Test that apply has deleted the fields
kube::test::get_object_assert foos/test-list '{{.otherField}}' '<no value>'
kube::test::get_object_assert bars/test-list '{{.otherField}}' '<no value>'

# Test that the fields does not exist
kube::test::get_object_assert foos/test-list '{{.newField}}' '<no value>'
kube::test::get_object_assert bars/test-list '{{.newField}}' '<no value>'

# Add a field and then apply the change
kubectl "${kube_flags[@]}" apply -f hack/testdata/TPR/multi-tpr-list-added-field.yaml

# Test that apply has added the field
kube::test::get_object_assert foos/test-list '{{.newField}}' 'field3'
kube::test::get_object_assert bars/test-list '{{.newField}}' 'field3'

# Delete the resource
kubectl "${kube_flags[@]}" delete -f hack/testdata/TPR/multi-tpr-list.yaml

# Make sure it's gone
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

## kubectl apply --prune
# Test that no foo or bar exist
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

# apply --prune on foo.yaml that has foo/test
kubectl apply --prune -l pruneGroup=true -f hack/testdata/TPR/foo.yaml "${kube_flags[@]}" --prune-whitelist=company.com/v1/Foo --prune-whitelist=company.com/v1/Bar
# check right tprs exist
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" 'test:'
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

# apply --prune on bar.yaml that has bar/test
kubectl apply --prune -l pruneGroup=true -f hack/testdata/TPR/bar.yaml "${kube_flags[@]}" --prune-whitelist=company.com/v1/Foo --prune-whitelist=company.com/v1/Bar
# check right tprs exist
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" 'test:'

# Delete the resource
kubectl "${kube_flags[@]}" delete -f hack/testdata/TPR/bar.yaml

# Make sure it's gone
kube::test::get_object_assert foos "{{range.items}}{{$id_field}}:{{end}}" ''
kube::test::get_object_assert bars "{{range.items}}{{$id_field}}:{{end}}" ''

# teardown
kubectl delete thirdpartyresources foo.company.com "${kube_flags[@]}"
kubectl delete thirdpartyresources bar.company.com "${kube_flags[@]}"
Expand Down
8 changes: 8 additions & 0 deletions hack/testdata/TPR/bar.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: Bar
apiVersion: company.com/v1
metadata:
name: test
labels:
pruneGroup: "true"
someField: field1
otherField: field2
11 changes: 11 additions & 0 deletions hack/testdata/TPR/foo-added-subfield.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: Foo
apiVersion: company.com/v1
metadata:
name: test
labels:
pruneGroup: "true"
someField: field1
otherField: field2
nestedField:
someSubfield: modifiedSubfield
newSubfield: subfield3
10 changes: 10 additions & 0 deletions hack/testdata/TPR/foo-deleted-subfield.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
kind: Foo
apiVersion: company.com/v1
metadata:
name: test
labels:
pruneGroup: "true"
someField: field1
otherField: field2
nestedField:
someSubfield: modifiedSubfield
11 changes: 11 additions & 0 deletions hack/testdata/TPR/foo-updated-subfield.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: Foo
apiVersion: company.com/v1
metadata:
name: test
labels:
pruneGroup: "true"
someField: field1
otherField: field2
nestedField:
someSubfield: modifiedSubfield
otherSubfield: subfield2
11 changes: 11 additions & 0 deletions hack/testdata/TPR/foo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
kind: Foo
apiVersion: company.com/v1
metadata:
name: test
labels:
pruneGroup: "true"
someField: field1
otherField: field2
nestedField:
someSubfield: subfield1
otherSubfield: subfield2
19 changes: 19 additions & 0 deletions hack/testdata/TPR/multi-tpr-list-added-field.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
kind: List
items:
- kind: Foo
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
newField: field3
- kind: Bar
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
newField: field3
17 changes: 17 additions & 0 deletions hack/testdata/TPR/multi-tpr-list-deleted-field.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: v1
kind: List
items:
- kind: Foo
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
- kind: Bar
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
19 changes: 19 additions & 0 deletions hack/testdata/TPR/multi-tpr-list-updated-field.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
kind: List
items:
- kind: Foo
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
otherField: field2
- kind: Bar
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: modifiedField
otherField: field2
19 changes: 19 additions & 0 deletions hack/testdata/TPR/multi-tpr-list.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
kind: List
items:
- kind: Foo
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: field1
otherField: field2
- kind: Bar
apiVersion: company.com/v1
metadata:
name: test-list
labels:
pruneGroup: "true"
someField: field1
otherField: field2
1 change: 1 addition & 0 deletions pkg/kubectl/cmd/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/json",
"//vendor:k8s.io/apimachinery/pkg/util/jsonmergepatch",
"//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/strategicpatch",
"//vendor:k8s.io/apimachinery/pkg/util/validation",
Expand Down

0 comments on commit 99def0d

Please sign in to comment.