Add "fieldManager" to flag to PATCH/CREATE/UPDATE

And add a corresponding flag in kubectl (for apply), even though the
value is defaulted in kubectl with "kubectl".

The flag is required for Apply patch-type, and optional for other PATCH,
CREATE and UPDATE (in which case we fallback on the user-agent).
This commit is contained in:
Antoine Pelisse
2019-02-16 20:16:11 -08:00
parent 8bde75e63f
commit eb904d8fa8
20 changed files with 378 additions and 34 deletions

View File

@@ -249,12 +249,12 @@ run_kubectl_apply_tests() {
set -o errexit
create_and_use_new_namespace
kube::log::status "Testing kubectl apply --server-side"
kube::log::status "Testing kubectl apply --experimental-server-side"
## kubectl apply should create the resource that doesn't exist yet
# Pre-Condition: no POD exists
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
# Command: apply a pod "test-pod" (doesn't exist) should create this pod
kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]}"
kubectl apply --experimental-server-side -f hack/testdata/pod.yaml "${kube_flags[@]}"
# Post-Condition: pod "test-pod" is created
kube::test::get_object_assert 'pods test-pod' "{{${labels_field}.name}}" 'test-pod-label'
# Clean up
@@ -265,13 +265,13 @@ run_kubectl_apply_tests() {
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
# apply dry-run
kubectl apply --server-side --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]}"
kubectl apply --experimental-server-side --server-dry-run -f hack/testdata/pod.yaml "${kube_flags[@]}"
# No pod exists
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" ''
# apply non dry-run creates the pod
kubectl apply --server-side -f hack/testdata/pod.yaml "${kube_flags[@]}"
kubectl apply --experimental-server-side -f hack/testdata/pod.yaml "${kube_flags[@]}"
# apply changes
kubectl apply --server-side --server-dry-run -f hack/testdata/pod-apply.yaml "${kube_flags[@]}"
kubectl apply --experimental-server-side --server-dry-run -f hack/testdata/pod-apply.yaml "${kube_flags[@]}"
# Post-Condition: label still has initial value
kube::test::get_object_assert 'pods test-pod' "{{${labels_field}.name}}" 'test-pod-label'
@@ -302,7 +302,7 @@ run_kubectl_apply_tests() {
__EOF__
# Dry-run create the CR
kubectl "${kube_flags[@]}" apply --server-side --server-dry-run -f hack/testdata/CRD/resource.yaml "${kube_flags[@]}"
kubectl "${kube_flags[@]}" apply --experimental-server-side --server-dry-run -f hack/testdata/CRD/resource.yaml "${kube_flags[@]}"
# Make sure that the CR doesn't exist
! kubectl "${kube_flags[@]}" get resource/myobj

View File

@@ -2,10 +2,15 @@ load("@io_bazel_rules_go//go:def.bzl", "go_test")
go_test(
name = "go_default_test",
size = "large",
srcs = [
"apply_test.go",
"main_test.go",
],
tags = [
"etcd",
"integration",
],
deps = [
"//pkg/master:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",

View File

@@ -106,6 +106,7 @@ func TestApplyAlsoCreates(t *testing.T) {
Namespace("default").
Resource(tc.resource).
Name(tc.name).
Param("fieldManager", "apply_test").
Body([]byte(tc.body)).
Do().
Get()
@@ -132,6 +133,7 @@ func TestCreateOnApplyFailsWithUID(t *testing.T) {
Namespace("default").
Resource("pods").
Name("test-pod-uid").
Param("fieldManager", "apply_test").
Body([]byte(`{
"apiVersion": "v1",
"kind": "Pod",
@@ -194,6 +196,7 @@ func TestApplyUpdateApplyConflictForced(t *testing.T) {
Namespace("default").
Resource("deployments").
Name("deployment").
Param("fieldManager", "apply_test").
Body(obj).Do().Get()
if err != nil {
t.Fatalf("Failed to create object using Apply patch: %v", err)
@@ -214,6 +217,7 @@ func TestApplyUpdateApplyConflictForced(t *testing.T) {
Namespace("default").
Resource("deployments").
Name("deployment").
Param("fieldManager", "apply_test").
Body([]byte(obj)).Do().Get()
if err == nil {
t.Fatalf("Expecting to get conflicts when applying object")
@@ -232,6 +236,7 @@ func TestApplyUpdateApplyConflictForced(t *testing.T) {
Resource("deployments").
Name("deployment").
Param("force", "true").
Param("fieldManager", "apply_test").
Body([]byte(obj)).Do().Get()
if err != nil {
t.Fatalf("Failed to apply object with force: %v", err)
@@ -249,6 +254,7 @@ func TestApplyManagedFields(t *testing.T) {
Namespace("default").
Resource("configmaps").
Name("test-cm").
Param("fieldManager", "apply_test").
Body([]byte(`{
"apiVersion": "v1",
"kind": "ConfigMap",
@@ -273,6 +279,7 @@ func TestApplyManagedFields(t *testing.T) {
Namespace("default").
Resource("configmaps").
Name("test-cm").
Param("fieldManager", "updater").
Body([]byte(`{"data":{"key": "new value"}}`)).Do().Get()
if err != nil {
t.Fatalf("Failed to patch object: %v", err)
@@ -306,7 +313,7 @@ func TestApplyManagedFields(t *testing.T) {
},
"managedFields": [
{
"manager": "apply",
"manager": "apply_test",
"operation": "Apply",
"apiVersion": "v1",
"fields": {
@@ -318,7 +325,7 @@ func TestApplyManagedFields(t *testing.T) {
}
},
{
"manager": "` + accessor.GetManagedFields()[1].Manager + `",
"manager": "updater",
"operation": "Update",
"apiVersion": "v1",
"time": "` + accessor.GetManagedFields()[1].Time.UTC().Format(time.RFC3339) + `",
@@ -360,6 +367,7 @@ func TestApplyRemovesEmptyManagedFields(t *testing.T) {
Namespace("default").
Resource("configmaps").
Name("test-cm").
Param("fieldManager", "apply_test").
Body(obj).
Do().
Get()
@@ -371,6 +379,7 @@ func TestApplyRemovesEmptyManagedFields(t *testing.T) {
Namespace("default").
Resource("configmaps").
Name("test-cm").
Param("fieldManager", "apply_test").
Body(obj).Do().Get()
if err != nil {
t.Fatalf("Failed to patch object: %v", err)
@@ -390,3 +399,42 @@ func TestApplyRemovesEmptyManagedFields(t *testing.T) {
t.Fatalf("Object contains unexpected managedFields: %v", managed)
}
}
func TestApplyRequiresFieldManager(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
_, client, closeFn := setup(t)
defer closeFn()
obj := []byte(`{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "test-cm",
"namespace": "default"
}
}`)
_, err := client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
Namespace("default").
Resource("configmaps").
Name("test-cm").
Body(obj).
Do().
Get()
if err == nil {
t.Fatalf("Apply should fail to create without fieldManager")
}
_, err = client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
Namespace("default").
Resource("configmaps").
Name("test-cm").
Param("fieldManager", "apply_test").
Body(obj).
Do().
Get()
if err != nil {
t.Fatalf("Apply failed to create with fieldManager: %v", err)
}
}

View File

@@ -567,6 +567,9 @@ func TestRBAC(t *testing.T) {
if r.verb == "PATCH" {
// For patch operations, use the apply content type
req.Header.Add("Content-Type", string(types.ApplyPatchType))
q := req.URL.Query()
q.Add("fieldManager", "rbac_test")
req.URL.RawQuery = q.Encode()
}
if err != nil {