diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index ffef1b059eb..ab49a0307ef 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -8891,7 +8891,8 @@ "type": "string" }, "description": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "overhead": { "additionalProperties": { @@ -9520,7 +9521,8 @@ "type": "string" }, "description": "Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "template": { "$ref": "#/definitions/io.k8s.api.core.v1.PodTemplateSpec", @@ -10441,7 +10443,8 @@ "type": "string" }, "description": "Route service traffic to pods with label keys and values matching this selector. If empty or not present, the service is assumed to have an external process managing its endpoints, which Kubernetes will not modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if type is ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "sessionAffinity": { "description": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies", @@ -13329,7 +13332,8 @@ "type": "string" }, "description": "nodeSelector lists labels that must be present on nodes that support this RuntimeClass. Pods using this RuntimeClass can only be scheduled to a node matched by this selector. The RuntimeClass nodeSelector is merged with a pod's existing nodeSelector. Any conflicts will cause the pod to be rejected in admission.", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "tolerations": { "description": "tolerations are appended (excluding duplicates) to pods running with this RuntimeClass during admission, effectively unioning the set of nodes tolerated by the pod and the RuntimeClass.", @@ -13451,7 +13455,8 @@ "type": "string" }, "description": "nodeSelector lists labels that must be present on nodes that support this RuntimeClass. Pods using this RuntimeClass can only be scheduled to a node matched by this selector. The RuntimeClass nodeSelector is merged with a pod's existing nodeSelector. Any conflicts will cause the pod to be rejected in admission.", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "tolerations": { "description": "tolerations are appended (excluding duplicates) to pods running with this RuntimeClass during admission, effectively unioning the set of nodes tolerated by the pod and the RuntimeClass.", @@ -13560,7 +13565,8 @@ "type": "string" }, "description": "nodeSelector lists labels that must be present on nodes that support this RuntimeClass. Pods using this RuntimeClass can only be scheduled to a node matched by this selector. The RuntimeClass nodeSelector is merged with a pod's existing nodeSelector. Any conflicts will cause the pod to be rejected in admission.", - "type": "object" + "type": "object", + "x-kubernetes-map-type": "atomic" }, "tolerations": { "description": "tolerations are appended (excluding duplicates) to pods running with this RuntimeClass during admission, effectively unioning the set of nodes tolerated by the pod and the RuntimeClass.", diff --git a/staging/src/k8s.io/api/apps/v1beta2/generated.proto b/staging/src/k8s.io/api/apps/v1beta2/generated.proto index ff306ba6a9a..8940f642690 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/generated.proto +++ b/staging/src/k8s.io/api/apps/v1beta2/generated.proto @@ -592,6 +592,7 @@ message ScaleStatus { // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors // +optional + // +mapType=atomic map selector = 2; // label selector for pods that should match the replicas count. This is a serializated diff --git a/staging/src/k8s.io/api/apps/v1beta2/types.go b/staging/src/k8s.io/api/apps/v1beta2/types.go index 316a0ad24d2..e94e29aea78 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/types.go +++ b/staging/src/k8s.io/api/apps/v1beta2/types.go @@ -45,6 +45,7 @@ type ScaleStatus struct { // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors // +optional + // +mapType=atomic Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,2,rep,name=selector"` // label selector for pods that should match the replicas count. This is a serializated diff --git a/staging/src/k8s.io/api/core/v1/generated.proto b/staging/src/k8s.io/api/core/v1/generated.proto index 152ea29fd05..e0fe9ef4f56 100644 --- a/staging/src/k8s.io/api/core/v1/generated.proto +++ b/staging/src/k8s.io/api/core/v1/generated.proto @@ -3450,6 +3450,7 @@ message PodSpec { // Selector which must match a node's labels for the pod to be scheduled on that node. // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ // +optional + // +mapType=atomic map nodeSelector = 7; // ServiceAccountName is the name of the ServiceAccount to use to run this pod. @@ -4138,6 +4139,7 @@ message ReplicationControllerSpec { // controller, if empty defaulted to labels on Pod template. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors // +optional + // +mapType=atomic map selector = 2; // Template is the object that describes the pod that will be created if @@ -4841,6 +4843,7 @@ message ServiceSpec { // Ignored if type is ExternalName. // More info: https://kubernetes.io/docs/concepts/services-networking/service/ // +optional + // +mapType=atomic map selector = 2; // clusterIP is the IP address of the service and is usually assigned diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index 3eadb45674c..ea7635f3cf7 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -3005,6 +3005,7 @@ type PodSpec struct { // Selector which must match a node's labels for the pod to be scheduled on that node. // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ // +optional + // +mapType=atomic NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,7,rep,name=nodeSelector"` // ServiceAccountName is the name of the ServiceAccount to use to run this pod. @@ -3785,6 +3786,7 @@ type ReplicationControllerSpec struct { // controller, if empty defaulted to labels on Pod template. // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors // +optional + // +mapType=atomic Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,2,rep,name=selector"` // TemplateRef is a reference to an object that describes the pod that will be created if @@ -4083,6 +4085,7 @@ type ServiceSpec struct { // Ignored if type is ExternalName. // More info: https://kubernetes.io/docs/concepts/services-networking/service/ // +optional + // +mapType=atomic Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,2,rep,name=selector"` // clusterIP is the IP address of the service and is usually assigned diff --git a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto index 5e3d165ebe6..a3e54810d62 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/extensions/v1beta1/generated.proto @@ -1237,6 +1237,7 @@ message ScaleStatus { // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors // +optional + // +mapType=atomic map selector = 2; // label selector for pods that should match the replicas count. This is a serializated diff --git a/staging/src/k8s.io/api/extensions/v1beta1/types.go b/staging/src/k8s.io/api/extensions/v1beta1/types.go index f3479713c53..5f5f51dc485 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/types.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/types.go @@ -37,6 +37,7 @@ type ScaleStatus struct { // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors // +optional + // +mapType=atomic Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,2,rep,name=selector"` // label selector for pods that should match the replicas count. This is a serializated diff --git a/staging/src/k8s.io/api/node/v1/generated.proto b/staging/src/k8s.io/api/node/v1/generated.proto index 4a86999f147..0b98cabb2f6 100644 --- a/staging/src/k8s.io/api/node/v1/generated.proto +++ b/staging/src/k8s.io/api/node/v1/generated.proto @@ -97,6 +97,7 @@ message Scheduling { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic map nodeSelector = 1; // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/api/node/v1/types.go b/staging/src/k8s.io/api/node/v1/types.go index b32cc36c496..bfe947e1fcd 100644 --- a/staging/src/k8s.io/api/node/v1/types.go +++ b/staging/src/k8s.io/api/node/v1/types.go @@ -82,6 +82,7 @@ type Scheduling struct { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,1,opt,name=nodeSelector"` // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/api/node/v1alpha1/generated.proto b/staging/src/k8s.io/api/node/v1alpha1/generated.proto index 310ad490bf9..967e06cc294 100644 --- a/staging/src/k8s.io/api/node/v1alpha1/generated.proto +++ b/staging/src/k8s.io/api/node/v1alpha1/generated.proto @@ -106,6 +106,7 @@ message Scheduling { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic map nodeSelector = 1; // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/api/node/v1alpha1/types.go b/staging/src/k8s.io/api/node/v1alpha1/types.go index 03e7e6f333b..58b84409f5f 100644 --- a/staging/src/k8s.io/api/node/v1alpha1/types.go +++ b/staging/src/k8s.io/api/node/v1alpha1/types.go @@ -91,6 +91,7 @@ type Scheduling struct { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,1,opt,name=nodeSelector"` // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/api/node/v1beta1/generated.proto b/staging/src/k8s.io/api/node/v1beta1/generated.proto index 5c2d9d50afa..724465902e2 100644 --- a/staging/src/k8s.io/api/node/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/node/v1beta1/generated.proto @@ -96,6 +96,7 @@ message Scheduling { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic map nodeSelector = 1; // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/api/node/v1beta1/types.go b/staging/src/k8s.io/api/node/v1beta1/types.go index 89559949ca5..5c0421efcb2 100644 --- a/staging/src/k8s.io/api/node/v1beta1/types.go +++ b/staging/src/k8s.io/api/node/v1beta1/types.go @@ -83,6 +83,7 @@ type Scheduling struct { // with a pod's existing nodeSelector. Any conflicts will cause the pod to // be rejected in admission. // +optional + // +mapType=atomic NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,1,opt,name=nodeSelector"` // tolerations are appended (excluding duplicates) to pods running with this diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go index 1d33039d628..c4d29e9e10d 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/fieldmanager_test.go @@ -79,6 +79,7 @@ func (d *fakeObjectDefaulter) Default(in runtime.Object) {} type TestFieldManager struct { fieldManager *FieldManager + apiVersion string emptyObj runtime.Object liveObj runtime.Object } @@ -122,6 +123,7 @@ func NewTestFieldManager(gvk schema.GroupVersionKind, ignoreManagedFieldsFromReq } return TestFieldManager{ fieldManager: NewFieldManager(f, ignoreManagedFieldsFromRequestObject), + apiVersion: gvk.GroupVersion().String(), emptyObj: live, liveObj: live.DeepCopyObject(), } @@ -147,10 +149,18 @@ func NewFakeOpenAPIModels() proto.Models { return m } +func (f *TestFieldManager) APIVersion() string { + return f.apiVersion +} + func (f *TestFieldManager) Reset() { f.liveObj = f.emptyObj.DeepCopyObject() } +func (f *TestFieldManager) Get() runtime.Object { + return f.liveObj.DeepCopyObject() +} + func (f *TestFieldManager) Apply(obj runtime.Object, manager string, force bool) error { out, err := f.fieldManager.Apply(f.liveObj, obj, manager, force) if err == nil { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/lastappliedmanager_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/lastappliedmanager_test.go index f6a2872d748..a7efed2ea68 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/lastappliedmanager_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/lastappliedmanager_test.go @@ -21,6 +21,7 @@ import ( "reflect" "testing" + apiequality "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -30,19 +31,21 @@ import ( "sigs.k8s.io/yaml" ) +type testArgs struct { + lastApplied []byte + original []byte + applied []byte + fieldManager string + expectConflictSet *fieldpath.Set +} + // TestApplyUsingLastAppliedAnnotation tests that applying to an object // created with the client-side apply last-applied annotation // will not give conflicts func TestApplyUsingLastAppliedAnnotation(t *testing.T) { f := NewDefaultTestFieldManager(schema.FromAPIVersionAndKind("apps/v1", "Deployment")) - tests := []struct { - lastApplied []byte - original []byte - applied []byte - fieldManager string - expectConflictSet *fieldpath.Set - }{ + tests := []testArgs{ { fieldManager: "kubectl", lastApplied: []byte(` @@ -556,6 +559,362 @@ spec: }, } + testConflicts(t, f, tests) +} + +func TestServiceApply(t *testing.T) { + f := NewDefaultTestFieldManager(schema.FromAPIVersionAndKind("v1", "Service")) + + tests := []testArgs{ + { + fieldManager: "kubectl", + original: []byte(` +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8443 + selector: + old: test +`), + applied: []byte(` +# All accepted while using the same field manager + +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8444 + selector: + new: test +`), + }, + { + fieldManager: "kubectl", + original: []byte(` +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8443 + selector: + old: test +`), + applied: []byte(` +# Allowed to remove selectors while using the same field manager + +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8444 + selector: {} +`), + }, + { + fieldManager: "not_kubectl", + original: []byte(` +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP # TODO: issue - this is a defaulted field, should not be required in a new spec + targetPort: 8443 + selector: + old: test +`), + applied: []byte(` +# test selector update not allowed by last-applied + +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8444 + selector: + new: test +`), + expectConflictSet: fieldpath.NewSet( + fieldpath.MakePathOrDie("spec", "selector"), // selector is atomic + fieldpath.MakePathOrDie("spec", "ports", fieldpath.KeyByFields("port", 443, "protocol", "TCP"), "targetPort"), + ), + }, + } + + testConflicts(t, f, tests) +} + +func TestReplicationControllerApply(t *testing.T) { + f := NewDefaultTestFieldManager(schema.FromAPIVersionAndKind("v1", "ReplicationController")) + + tests := []testArgs{ + { + fieldManager: "kubectl", + original: []byte(` +apiVersion: v1 +kind: ReplicationController +metadata: + name: test +spec: + replicas: 0 + selector: + old: test +`), + applied: []byte(` +# All accepted while using the same field manager + +apiVersion: v1 +kind: ReplicationController +metadata: + name: test +spec: + replicas: 3 + selector: + new: test +`), + }, + { + fieldManager: "not_kubectl", + original: []byte(` +apiVersion: v1 +kind: ReplicationController +metadata: + name: test +spec: + replicas: 0 + selector: + old: test +`), + applied: []byte(` +# test selector update not allowed by last-applied + +apiVersion: v1 +kind: ReplicationController +metadata: + name: test +spec: + replicas: 3 + selector: + new: test +`), + expectConflictSet: fieldpath.NewSet( + fieldpath.MakePathOrDie("spec", "selector"), // selector is atomic + fieldpath.MakePathOrDie("spec", "replicas"), + ), + }, + } + + testConflicts(t, f, tests) +} + +func TestPodApply(t *testing.T) { + f := NewDefaultTestFieldManager(schema.FromAPIVersionAndKind("v1", "Pod")) + + tests := []testArgs{ + { + fieldManager: "kubectl", + original: []byte(` +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: definetlyControlPlane + nodeSelector: + node-role.kubernetes.io/master: "" +`), + applied: []byte(` +# All accepted while using the same field manager + +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeSelector: + node-role.kubernetes.io/worker: "" +`), + }, + { + fieldManager: "not_kubectl", + original: []byte(` +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: definetlyControlPlane + nodeSelector: + node-role.kubernetes.io/master: "" +`), + applied: []byte(` +# test selector update not allowed by last-applied + +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: definetlyControlPlane + nodeSelector: + node-role.kubernetes.io/master: "" + otherNodeType: "" +`), + expectConflictSet: fieldpath.NewSet( + fieldpath.MakePathOrDie("spec", "nodeSelector"), // selector is atomic + ), + }, + { + fieldManager: "not_kubectl", + original: []byte(` +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: definetlyControlPlane + nodeSelector: + node-role.kubernetes.io/master: "" +`), + applied: []byte(` +# purging selector not allowed for different manager + +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: another + nodeSelector: {} +`), + expectConflictSet: fieldpath.NewSet( + fieldpath.MakePathOrDie("spec", "nodeSelector"), // selector is atomic + fieldpath.MakePathOrDie("spec", "nodeName"), + ), + }, + { + fieldManager: "kubectl", + original: []byte(` +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: definetlyControlPlane + nodeSelector: + node-role.kubernetes.io/master: "" +`), + applied: []byte(` +# same manager could purge nodeSelector + +apiVersion: v1 +kind: Pod +metadata: + name: test + namespace: test +spec: + containers: + - args: + - -v=2 + command: + - controller + image: some.registry/app:latest + name: doJob + nodeName: another + nodeSelector: {} +`), + }, + } + + testConflicts(t, f, tests) +} + +func testConflicts(t *testing.T, f TestFieldManager, tests []testArgs) { for i, test := range tests { t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) { f.Reset() @@ -587,23 +946,34 @@ spec: if err != nil { t.Errorf("expected no error but got %v", err) } - return - } + } else { + if err == nil || !apierrors.IsConflict(err) { + t.Errorf("expected to get conflicts but got %v", err) + } - if err == nil || !apierrors.IsConflict(err) { - t.Errorf("expected to get conflicts but got %v", err) - } - - expectedConflicts := merge.Conflicts{} - test.expectConflictSet.Iterate(func(p fieldpath.Path) { - expectedConflicts = append(expectedConflicts, merge.Conflict{ - Manager: `{"manager":"test_client_side_apply","operation":"Update","apiVersion":"apps/v1"}`, - Path: p, + expectedConflicts := merge.Conflicts{} + test.expectConflictSet.Iterate(func(p fieldpath.Path) { + expectedConflicts = append(expectedConflicts, merge.Conflict{ + Manager: fmt.Sprintf(`{"manager":"test_client_side_apply","operation":"Update","apiVersion":"%s"}`, f.APIVersion()), + Path: p, + }) }) - }) - expectedConflictErr := internal.NewConflictError(expectedConflicts) - if !reflect.DeepEqual(expectedConflictErr, err) { - t.Errorf("expected to get\n%+v\nbut got\n%+v", expectedConflictErr, err) + expectedConflictErr := internal.NewConflictError(expectedConflicts) + if !reflect.DeepEqual(expectedConflictErr, err) { + t.Errorf("expected to get\n%+v\nbut got\n%+v", expectedConflictErr, err) + } + + // Yet force should resolve all conflicts + err = f.Apply(appliedObj, test.fieldManager, true) + if err != nil { + t.Errorf("unexpected error during force ownership apply: %v", err) + } + + } + + // Eventually resource should contain applied changes + if !apiequality.Semantic.DeepDerivative(appliedObj, f.Get()) { + t.Errorf("expected equal resource: \n%#v, got: \n%#v", appliedObj, f.Get()) } }) } diff --git a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go index abe43c0bf47..69cd3ae78f8 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go @@ -5290,6 +5290,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: overhead type: map: @@ -5673,6 +5674,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: template type: namedType: io.k8s.api.core.v1.PodTemplateSpec @@ -6195,6 +6197,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: sessionAffinity type: scalar: string @@ -8859,6 +8862,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: tolerations type: list: @@ -8911,6 +8915,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: tolerations type: list: @@ -8956,6 +8961,7 @@ var schemaYAML = typed.YAMLObject(`types: map: elementType: scalar: string + elementRelationship: atomic - name: tolerations type: list: