diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 1a969a99eeb..b27589f30e2 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -60956,7 +60956,7 @@ "$ref": "#/definitions/io.k8s.api.core.v1.Volume" }, "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" + "x-kubernetes-patch-strategy": "merge,retainKeys" } } }, @@ -62775,6 +62775,7 @@ }, "strategy": { "description": "The deployment strategy to use to replace existing pods with new ones.", + "x-kubernetes-patch-strategy": "retainKeys", "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentStrategy" }, "template": { diff --git a/federation/apis/openapi-spec/swagger.json b/federation/apis/openapi-spec/swagger.json index 907c959ca5e..3336486d3d1 100644 --- a/federation/apis/openapi-spec/swagger.json +++ b/federation/apis/openapi-spec/swagger.json @@ -11237,7 +11237,7 @@ "$ref": "#/definitions/io.k8s.api.core.v1.Volume" }, "x-kubernetes-patch-merge-key": "name", - "x-kubernetes-patch-strategy": "merge" + "x-kubernetes-patch-strategy": "merge,retainKeys" } } }, @@ -12530,6 +12530,7 @@ }, "strategy": { "description": "The deployment strategy to use to replace existing pods with new ones.", + "x-kubernetes-patch-strategy": "retainKeys", "$ref": "#/definitions/io.k8s.api.extensions.v1beta1.DeploymentStrategy" }, "template": { diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index 0c2c61ce05b..a7ac65f198f 100755 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -932,6 +932,30 @@ run_kubectl_apply_tests() { kubectl delete pods test-pod "${kube_flags[@]}" + ## kubectl apply should be able to clear defaulted fields. + # Pre-Condition: no deployment exists + kube::test::get_object_assert deployments "{{range.items}}{{$id_field}}:{{end}}" '' + # Command: apply a deployment "test-deployment-retainkeys" (doesn't exist) should create this deployment + kubectl apply -f hack/testdata/retainKeys/deployment/deployment-before.yaml "${kube_flags[@]}" + # Post-Condition: deployment "test-deployment-retainkeys" created + kube::test::get_object_assert deployments "{{range.items}}{{$id_field}}{{end}}" 'test-deployment-retainkeys' + # Post-Condition: deployment "test-deployment-retainkeys" has defaulted fields + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep RollingUpdate)" ]] + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep maxSurge)" ]] + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep maxUnavailable)" ]] + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep emptyDir)" ]] + # Command: apply a deployment "test-deployment-retainkeys" should clear + # defaulted fields and successfully update the deployment + [[ "$(kubectl apply -f hack/testdata/retainKeys/deployment/deployment-after.yaml "${kube_flags[@]}")" ]] + # Post-Condition: deployment "test-deployment-retainkeys" has updated fields + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep Recreate)" ]] + ! [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep RollingUpdate)" ]] + [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep hostPath)" ]] + ! [[ "$(kubectl get deployments test-deployment-retainkeys -o yaml "${kube_flags[@]}" | grep emptyDir)" ]] + # Clean up + kubectl delete deployments test-deployment-retainkeys "${kube_flags[@]}" + + ## kubectl apply -f with label selector should only apply matching objects # Pre-Condition: no POD exists kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" '' diff --git a/hack/testdata/retainKeys/deployment/deployment-after.yaml b/hack/testdata/retainKeys/deployment/deployment-after.yaml new file mode 100644 index 00000000000..15689a59959 --- /dev/null +++ b/hack/testdata/retainKeys/deployment/deployment-after.yaml @@ -0,0 +1,22 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: test-deployment-retainkeys +spec: + strategy: + type: Recreate + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + ports: + - containerPort: 80 + volumes: + - name: test-volume + hostPath: + path: /data diff --git a/hack/testdata/retainKeys/deployment/deployment-before.yaml b/hack/testdata/retainKeys/deployment/deployment-before.yaml new file mode 100644 index 00000000000..e58a0c34a14 --- /dev/null +++ b/hack/testdata/retainKeys/deployment/deployment-before.yaml @@ -0,0 +1,18 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: test-deployment-retainkeys +spec: + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + ports: + - containerPort: 80 + volumes: + - name: test-volume diff --git a/staging/src/k8s.io/api/core/v1/generated.proto b/staging/src/k8s.io/api/core/v1/generated.proto index ddb0780bd5f..fda350d46c7 100644 --- a/staging/src/k8s.io/api/core/v1/generated.proto +++ b/staging/src/k8s.io/api/core/v1/generated.proto @@ -2720,7 +2720,7 @@ message PodSpec { // More info: https://kubernetes.io/docs/concepts/storage/volumes // +optional // +patchMergeKey=name - // +patchStrategy=merge + // +patchStrategy=merge,retainKeys repeated Volume volumes = 1; // List of initialization containers belonging to the pod. diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index 719b1d82a76..45f441755e5 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -2494,8 +2494,8 @@ type PodSpec struct { // More info: https://kubernetes.io/docs/concepts/storage/volumes // +optional // +patchMergeKey=name - // +patchStrategy=merge - Volumes []Volume `json:"volumes,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + // +patchStrategy=merge,retainKeys + Volumes []Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` // List of initialization containers belonging to the pod. // Init containers are executed in order prior to containers being started. If any // init container fails, the pod is considered to have failed and is handled according diff --git a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto index 87a2f91687b..0b319f99712 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto @@ -276,6 +276,7 @@ message DeploymentSpec { // The deployment strategy to use to replace existing pods with new ones. // +optional + // +patchStrategy=retainKeys optional DeploymentStrategy strategy = 4; // Minimum number of seconds for which a newly created pod should be ready diff --git a/staging/src/k8s.io/api/extensions/v1beta1/types.go b/staging/src/k8s.io/api/extensions/v1beta1/types.go index 2967f053b35..971db945bd0 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/types.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/types.go @@ -193,7 +193,8 @@ type DeploymentSpec struct { // The deployment strategy to use to replace existing pods with new ones. // +optional - Strategy DeploymentStrategy `json:"strategy,omitempty" protobuf:"bytes,4,opt,name=strategy"` + // +patchStrategy=retainKeys + Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" protobuf:"bytes,4,opt,name=strategy"` // Minimum number of seconds for which a newly created pod should be ready // without any of its container crashing, for it to be considered available.