1
16
17 package managedfields_test
18
19 import (
20 "encoding/json"
21 "fmt"
22 "net/http"
23 "os"
24 "path/filepath"
25 "reflect"
26 "strings"
27 "testing"
28 "time"
29
30 apierrors "k8s.io/apimachinery/pkg/api/errors"
31 "k8s.io/apimachinery/pkg/api/meta"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
34 "k8s.io/apimachinery/pkg/runtime"
35 "k8s.io/apimachinery/pkg/runtime/schema"
36 "k8s.io/apimachinery/pkg/util/managedfields"
37 "k8s.io/apimachinery/pkg/util/managedfields/internal"
38 "k8s.io/apimachinery/pkg/util/managedfields/managedfieldstest"
39 yamlutil "k8s.io/apimachinery/pkg/util/yaml"
40 "k8s.io/kube-openapi/pkg/validation/spec"
41 "sigs.k8s.io/yaml"
42 )
43
44 var fakeTypeConverter = func() managedfields.TypeConverter {
45 data, err := os.ReadFile(filepath.Join(strings.Repeat(".."+string(filepath.Separator), 7),
46 "api", "openapi-spec", "swagger.json"))
47 if err != nil {
48 panic(err)
49 }
50 swag := spec.Swagger{}
51 if err := json.Unmarshal(data, &swag); err != nil {
52 panic(err)
53 }
54 convertedDefs := map[string]*spec.Schema{}
55 for k, v := range swag.Definitions {
56 vCopy := v
57 convertedDefs[k] = &vCopy
58 }
59 typeConverter, err := managedfields.NewTypeConverter(convertedDefs, false)
60 if err != nil {
61 panic(err)
62 }
63 return typeConverter
64 }()
65
66
67
68 func TestUpdateApplyConflict(t *testing.T) {
69 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
70
71 patch := []byte(`{
72 "apiVersion": "apps/v1",
73 "kind": "Deployment",
74 "metadata": {
75 "name": "deployment",
76 "labels": {"app": "nginx"}
77 },
78 "spec": {
79 "replicas": 3,
80 "selector": {
81 "matchLabels": {
82 "app": "nginx"
83 }
84 },
85 "template": {
86 "metadata": {
87 "labels": {
88 "app": "nginx"
89 }
90 },
91 "spec": {
92 "containers": [{
93 "name": "nginx",
94 "image": "nginx:latest"
95 }]
96 }
97 }
98 }
99 }`)
100 newObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
101 if err := yaml.Unmarshal(patch, &newObj.Object); err != nil {
102 t.Fatalf("error decoding YAML: %v", err)
103 }
104
105 if err := f.Update(newObj, "fieldmanager_test"); err != nil {
106 t.Fatalf("failed to apply object: %v", err)
107 }
108
109 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
110 if err := yaml.Unmarshal([]byte(`{
111 "apiVersion": "apps/v1",
112 "kind": "Deployment",
113 "metadata": {
114 "name": "deployment",
115 },
116 "spec": {
117 "replicas": 101,
118 }
119 }`), &appliedObj.Object); err != nil {
120 t.Fatalf("error decoding YAML: %v", err)
121 }
122
123 err := f.Apply(appliedObj, "fieldmanager_conflict", false)
124 if err == nil || !apierrors.IsConflict(err) {
125 t.Fatalf("Expecting to get conflicts but got %v", err)
126 }
127 }
128
129 func TestApplyStripsFields(t *testing.T) {
130 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
131
132 newObj := &unstructured.Unstructured{
133 Object: map[string]interface{}{
134 "apiVersion": "apps/v1",
135 "kind": "Deployment",
136 },
137 }
138
139 newObj.SetName("b")
140 newObj.SetNamespace("b")
141 newObj.SetUID("b")
142 newObj.SetGeneration(0)
143 newObj.SetResourceVersion("b")
144 newObj.SetCreationTimestamp(metav1.NewTime(time.Now()))
145 newObj.SetManagedFields([]metav1.ManagedFieldsEntry{
146 {
147 Manager: "update",
148 Operation: metav1.ManagedFieldsOperationApply,
149 APIVersion: "apps/v1",
150 },
151 })
152 if err := f.Update(newObj, "fieldmanager_test"); err != nil {
153 t.Fatalf("failed to apply object: %v", err)
154 }
155
156 if m := f.ManagedFields(); len(m) != 0 {
157 t.Fatalf("fields did not get stripped: %v", m)
158 }
159 }
160
161 func TestVersionCheck(t *testing.T) {
162 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
163
164 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
165 if err := yaml.Unmarshal([]byte(`{
166 "apiVersion": "apps/v1",
167 "kind": "Deployment",
168 }`), &appliedObj.Object); err != nil {
169 t.Fatalf("error decoding YAML: %v", err)
170 }
171
172
173 err := f.Apply(appliedObj, "fieldmanager_test", false)
174 if err != nil {
175 t.Fatalf("failed to apply object: %v", err)
176 }
177
178 appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
179 if err := yaml.Unmarshal([]byte(`{
180 "apiVersion": "apps/v1beta1",
181 "kind": "Deployment",
182 }`), &appliedObj.Object); err != nil {
183 t.Fatalf("error decoding YAML: %v", err)
184 }
185
186
187 err = f.Apply(appliedObj, "fieldmanager_test", false)
188 if err == nil {
189 t.Fatalf("expected an error from mismatched patch and live versions")
190 }
191 switch typ := err.(type) {
192 default:
193 t.Fatalf("expected error to be of type %T was %T (%v)", apierrors.StatusError{}, typ, err)
194 case apierrors.APIStatus:
195 if typ.Status().Code != http.StatusBadRequest {
196 t.Fatalf("expected status code to be %d but was %d",
197 http.StatusBadRequest, typ.Status().Code)
198 }
199 }
200 }
201
202 func TestVersionCheckDoesNotPanic(t *testing.T) {
203 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
204
205 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
206 if err := yaml.Unmarshal([]byte(`{
207 "apiVersion": "apps/v1",
208 "kind": "Deployment",
209 }`), &appliedObj.Object); err != nil {
210 t.Fatalf("error decoding YAML: %v", err)
211 }
212
213
214 err := f.Apply(appliedObj, "fieldmanager_test", false)
215 if err != nil {
216 t.Fatalf("failed to apply object: %v", err)
217 }
218
219 appliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
220 if err := yaml.Unmarshal([]byte(`{
221 }`), &appliedObj.Object); err != nil {
222 t.Fatalf("error decoding YAML: %v", err)
223 }
224
225
226 err = f.Apply(appliedObj, "fieldmanager_test", false)
227 if err == nil {
228 t.Fatalf("expected an error from mismatched patch and live versions")
229 }
230 switch typ := err.(type) {
231 default:
232 t.Fatalf("expected error to be of type %T was %T (%v)", apierrors.StatusError{}, typ, err)
233 case apierrors.APIStatus:
234 if typ.Status().Code != http.StatusBadRequest {
235 t.Fatalf("expected status code to be %d but was %d",
236 http.StatusBadRequest, typ.Status().Code)
237 }
238 }
239 }
240
241 func TestApplyDoesNotStripLabels(t *testing.T) {
242 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
243
244 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
245 if err := yaml.Unmarshal([]byte(`{
246 "apiVersion": "v1",
247 "kind": "Pod",
248 "metadata": {
249 "labels": {
250 "a": "b"
251 },
252 }
253 }`), &appliedObj.Object); err != nil {
254 t.Fatalf("error decoding YAML: %v", err)
255 }
256
257 err := f.Apply(appliedObj, "fieldmanager_test", false)
258 if err != nil {
259 t.Fatalf("failed to apply object: %v", err)
260 }
261
262 if m := f.ManagedFields(); len(m) != 1 {
263 t.Fatalf("labels shouldn't get stripped on apply: %v", m)
264 }
265 }
266
267 func getObjectBytes(file string) []byte {
268 s, err := os.ReadFile(file)
269 if err != nil {
270 panic(err)
271 }
272 return s
273 }
274
275 func TestApplyNewObject(t *testing.T) {
276 tests := []struct {
277 gvk schema.GroupVersionKind
278 obj []byte
279 }{
280 {
281 gvk: schema.FromAPIVersionAndKind("v1", "Pod"),
282 obj: getObjectBytes("pod.yaml"),
283 },
284 {
285 gvk: schema.FromAPIVersionAndKind("v1", "Node"),
286 obj: getObjectBytes("node.yaml"),
287 },
288 {
289 gvk: schema.FromAPIVersionAndKind("v1", "Endpoints"),
290 obj: getObjectBytes("endpoints.yaml"),
291 },
292 }
293
294 for _, test := range tests {
295 t.Run(test.gvk.String(), func(t *testing.T) {
296 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, test.gvk)
297
298 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
299 if err := yaml.Unmarshal(test.obj, &appliedObj.Object); err != nil {
300 t.Fatalf("error decoding YAML: %v", err)
301 }
302
303 if err := f.Apply(appliedObj, "fieldmanager_test", false); err != nil {
304 t.Fatal(err)
305 }
306 })
307 }
308 }
309
310 func TestApplyFailsWithManagedFields(t *testing.T) {
311 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
312
313 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
314 if err := yaml.Unmarshal([]byte(`{
315 "apiVersion": "v1",
316 "kind": "Pod",
317 "metadata": {
318 "managedFields": [
319 {
320 "manager": "test",
321 }
322 ]
323 }
324 }`), &appliedObj.Object); err != nil {
325 t.Fatalf("error decoding YAML: %v", err)
326 }
327
328 err := f.Apply(appliedObj, "fieldmanager_test", false)
329
330 if err == nil {
331 t.Fatalf("successfully applied with set managed fields")
332 }
333 }
334
335 func TestApplySuccessWithNoManagedFields(t *testing.T) {
336 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
337
338 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
339 if err := yaml.Unmarshal([]byte(`{
340 "apiVersion": "v1",
341 "kind": "Pod",
342 "metadata": {
343 "labels": {
344 "a": "b"
345 },
346 }
347 }`), &appliedObj.Object); err != nil {
348 t.Fatalf("error decoding YAML: %v", err)
349 }
350 err := f.Apply(appliedObj, "fieldmanager_test", false)
351
352 if err != nil {
353 t.Fatalf("failed to apply object: %v", err)
354 }
355 }
356
357
358 func TestNoOpChanges(t *testing.T) {
359 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
360
361 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
362 if err := yaml.Unmarshal([]byte(`{
363 "apiVersion": "v1",
364 "kind": "Pod",
365 "metadata": {
366 "labels": {
367 "a": "b"
368 },
369 "creationTimestamp": null,
370 }
371 }`), &obj.Object); err != nil {
372 t.Fatalf("error decoding YAML: %v", err)
373 }
374 if err := f.Apply(obj.DeepCopyObject(), "fieldmanager_test_apply", false); err != nil {
375 t.Fatalf("failed to apply object: %v", err)
376 }
377 before := f.Live()
378
379 time.Sleep(time.Second)
380
381 if err := f.Apply(obj.DeepCopyObject(), "fieldmanager_test_apply_other", false); err != nil {
382 t.Fatalf("failed to update object: %v", err)
383 }
384 if reflect.DeepEqual(before, f.Live()) {
385 t.Fatalf("Applying no-op apply with new manager didn't change object: \n%v", f.Live())
386 }
387 before = f.Live()
388
389 time.Sleep(time.Second)
390 if err := f.Update(obj.DeepCopyObject(), "fieldmanager_test_update"); err != nil {
391 t.Fatalf("failed to update object: %v", err)
392 }
393 if !reflect.DeepEqual(before, f.Live()) {
394 t.Fatalf("No-op update has changed the object:\n%v\n---\n%v", before, f.Live())
395 }
396 before = f.Live()
397
398 time.Sleep(time.Second)
399 if err := f.Apply(obj.DeepCopyObject(), "fieldmanager_test_apply", true); err != nil {
400 t.Fatalf("failed to re-apply object: %v", err)
401 }
402 if !reflect.DeepEqual(before, f.Live()) {
403 t.Fatalf("No-op apply has changed the object:\n%v\n---\n%v", before, f.Live())
404 }
405 }
406
407
408
409 func TestResetManagedFieldsEmptyList(t *testing.T) {
410 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
411
412 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
413 if err := yaml.Unmarshal([]byte(`{
414 "apiVersion": "v1",
415 "kind": "Pod",
416 "metadata": {
417 "labels": {
418 "a": "b"
419 },
420 }
421 }`), &obj.Object); err != nil {
422 t.Fatalf("error decoding YAML: %v", err)
423 }
424 if err := f.Apply(obj, "fieldmanager_test_apply", false); err != nil {
425 t.Fatalf("failed to apply object: %v", err)
426 }
427
428 if err := yaml.Unmarshal([]byte(`{
429 "apiVersion": "v1",
430 "kind": "Pod",
431 "metadata": {
432 "managedFields": [],
433 "labels": {
434 "a": "b"
435 },
436 }
437 }`), &obj.Object); err != nil {
438 t.Fatalf("error decoding YAML: %v", err)
439 }
440 if err := f.Update(obj, "update_manager"); err != nil {
441 t.Fatalf("failed to update with empty manager: %v", err)
442 }
443
444 if len(f.ManagedFields()) != 0 {
445 t.Fatalf("failed to reset managedFields: %v", f.ManagedFields())
446 }
447 }
448
449
450 func TestResetManagedFieldsEmptyItem(t *testing.T) {
451 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"))
452
453 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
454 if err := yaml.Unmarshal([]byte(`{
455 "apiVersion": "v1",
456 "kind": "Pod",
457 "metadata": {
458 "labels": {
459 "a": "b"
460 },
461 }
462 }`), &obj.Object); err != nil {
463 t.Fatalf("error decoding YAML: %v", err)
464 }
465 if err := f.Apply(obj, "fieldmanager_test_apply", false); err != nil {
466 t.Fatalf("failed to apply object: %v", err)
467 }
468
469 if err := yaml.Unmarshal([]byte(`{
470 "apiVersion": "v1",
471 "kind": "Pod",
472 "metadata": {
473 "managedFields": [{}],
474 "labels": {
475 "a": "b"
476 },
477 }
478 }`), &obj.Object); err != nil {
479 t.Fatalf("error decoding YAML: %v", err)
480 }
481 if err := f.Update(obj, "update_manager"); err != nil {
482 t.Fatalf("failed to update with empty manager: %v", err)
483 }
484
485 if len(f.ManagedFields()) != 0 {
486 t.Fatalf("failed to reset managedFields: %v", f.ManagedFields())
487 }
488 }
489
490 func TestServerSideApplyWithInvalidLastApplied(t *testing.T) {
491 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
492
493
494 newObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
495 deployment := []byte(`
496 apiVersion: apps/v1
497 kind: Deployment
498 metadata:
499 name: my-deployment
500 labels:
501 app: my-app-v1
502 spec:
503 replicas: 1
504 `)
505 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
506 t.Errorf("error decoding YAML: %v", err)
507 }
508
509 invalidLastApplied := "invalid-object"
510 if err := internal.SetLastApplied(newObj, invalidLastApplied); err != nil {
511 t.Errorf("failed to set last applied: %v", err)
512 }
513
514 if err := f.Update(newObj, "kubectl-client-side-apply-test"); err != nil {
515 t.Errorf("failed to update object: %v", err)
516 }
517
518 lastApplied, err := getLastApplied(f.Live())
519 if err != nil {
520 t.Errorf("failed to get last applied: %v", err)
521 }
522 if lastApplied != invalidLastApplied {
523 t.Errorf("expected last applied annotation to be set to %q, but got: %q", invalidLastApplied, lastApplied)
524 }
525
526
527 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
528 appliedDeployment := []byte(`
529 apiVersion: apps/v1
530 kind: Deployment
531 metadata:
532 name: my-deployment
533 labels:
534 app: my-app-v2
535 spec:
536 replicas: 100
537 `)
538 if err := yaml.Unmarshal(appliedDeployment, &appliedObj.Object); err != nil {
539 t.Errorf("error decoding YAML: %v", err)
540 }
541
542 if err := f.Apply(appliedObj, "kubectl", false); err == nil || !apierrors.IsConflict(err) {
543 t.Errorf("expected conflict when applying with invalid last-applied annotation, but got no error for object: \n%+v", appliedObj)
544 }
545
546 lastApplied, err = getLastApplied(f.Live())
547 if err != nil {
548 t.Errorf("failed to get last applied: %v", err)
549 }
550 if lastApplied != invalidLastApplied {
551 t.Errorf("expected last applied annotation to be NOT be updated, but got: %q", lastApplied)
552 }
553
554
555 if err := f.Apply(appliedObj, "kubectl", true); err != nil {
556 t.Errorf("failed to force server-side apply with: %v", err)
557 }
558
559 lastApplied, err = getLastApplied(f.Live())
560 if err != nil {
561 t.Errorf("failed to get last applied: %v", err)
562 }
563 if lastApplied == invalidLastApplied ||
564 !strings.Contains(lastApplied, "my-app-v2") {
565 t.Errorf("expected last applied annotation to be updated, but got: %q", lastApplied)
566 }
567 }
568
569 func TestInteropForClientSideApplyAndServerSideApply(t *testing.T) {
570 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
571
572
573 newObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
574 deployment := []byte(`
575 apiVersion: apps/v1
576 kind: Deployment
577 metadata:
578 name: my-deployment
579 labels:
580 app: my-app
581 spec:
582 replicas: 100
583 selector:
584 matchLabels:
585 app: my-app
586 template:
587 metadata:
588 labels:
589 app: my-app
590 spec:
591 containers:
592 - name: my-c
593 image: my-image-v1
594 `)
595 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
596 t.Errorf("error decoding YAML: %v", err)
597 }
598 if err := setLastAppliedFromEncoded(newObj, deployment); err != nil {
599 t.Errorf("failed to set last applied: %v", err)
600 }
601
602 if err := f.Update(newObj, "kubectl-client-side-apply-test"); err != nil {
603 t.Errorf("failed to update object: %v", err)
604 }
605 lastApplied, err := getLastApplied(f.Live())
606 if err != nil {
607 t.Errorf("failed to get last applied: %v", err)
608 }
609 if !strings.Contains(lastApplied, "my-image-v1") {
610 t.Errorf("expected last applied annotation to be set properly, but got: %q", lastApplied)
611 }
612
613
614 appliedObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
615 appliedDeployment := []byte(`
616 apiVersion: apps/v1
617 kind: Deployment
618 metadata:
619 name: my-deployment
620 labels:
621 app: my-app-v2 # change
622 spec:
623 replicas: 8 # change
624 selector:
625 matchLabels:
626 app: my-app-v2 # change
627 template:
628 metadata:
629 labels:
630 app: my-app-v2 # change
631 spec:
632 containers:
633 - name: my-c
634 image: my-image-v2 # change
635 `)
636 if err := yaml.Unmarshal(appliedDeployment, &appliedObj.Object); err != nil {
637 t.Errorf("error decoding YAML: %v", err)
638 }
639
640 if err := f.Apply(appliedObj, "kubectl", false); err != nil {
641 t.Errorf("error applying object: %v", err)
642 }
643
644 lastApplied, err = getLastApplied(f.Live())
645 if err != nil {
646 t.Errorf("failed to get last applied: %v", err)
647 }
648 if !strings.Contains(lastApplied, "my-image-v2") {
649 t.Errorf("expected last applied annotation to be updated, but got: %q", lastApplied)
650 }
651 }
652
653 func TestNoTrackManagedFieldsForClientSideApply(t *testing.T) {
654 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
655
656
657 newObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
658 deployment := []byte(`
659 apiVersion: apps/v1
660 kind: Deployment
661 metadata:
662 name: my-deployment
663 labels:
664 app: my-app
665 spec:
666 replicas: 100
667 `)
668 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
669 t.Errorf("error decoding YAML: %v", err)
670 }
671 if err := f.Update(newObj, "test_kubectl_create"); err != nil {
672 t.Errorf("failed to update object: %v", err)
673 }
674 if m := f.ManagedFields(); len(m) == 0 {
675 t.Errorf("expected to have managed fields, but got: %v", m)
676 }
677
678
679 newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
680 deployment = []byte(`
681 apiVersion: apps/v1
682 kind: Deployment
683 metadata:
684 name: my-deployment
685 managedFields: [] # stop tracking managed fields
686 labels:
687 app: my-app
688 spec:
689 replicas: 100
690 `)
691 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
692 t.Errorf("error decoding YAML: %v", err)
693 }
694 newObj.SetUID("nonempty")
695 if err := f.Update(newObj, "test_kubectl_replace"); err != nil {
696 t.Errorf("failed to update object: %v", err)
697 }
698 if m := f.ManagedFields(); len(m) != 0 {
699 t.Errorf("expected to have stop tracking managed fields, but got: %v", m)
700 }
701
702
703 newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
704 deployment = []byte(`
705 apiVersion: apps/v1
706 kind: Deployment
707 metadata:
708 name: my-deployment
709 labels:
710 app: my-app
711 spec:
712 replicas: 100
713 `)
714 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
715 t.Errorf("error decoding YAML: %v", err)
716 }
717 if err := setLastAppliedFromEncoded(newObj, deployment); err != nil {
718 t.Errorf("failed to set last applied: %v", err)
719 }
720 if err := f.Update(newObj, "test_k_client_side_apply"); err != nil {
721 t.Errorf("failed to update object: %v", err)
722 }
723 if m := f.ManagedFields(); len(m) != 0 {
724 t.Errorf("expected to continue to not track managed fields, but got: %v", m)
725 }
726 lastApplied, err := getLastApplied(f.Live())
727 if err != nil {
728 t.Errorf("failed to get last applied: %v", err)
729 }
730 if !strings.Contains(lastApplied, "my-app") {
731 t.Errorf("expected last applied annotation to be set properly, but got: %q", lastApplied)
732 }
733
734
735 newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
736 deployment = []byte(`
737 apiVersion: apps/v1
738 kind: Deployment
739 metadata:
740 name: my-deployment
741 labels:
742 app: my-app
743 spec:
744 replicas: 100
745 `)
746 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
747 t.Errorf("error decoding YAML: %v", err)
748 }
749 if err := f.Apply(newObj, "test_server_side_apply_without_upgrade", false); err != nil {
750 t.Errorf("error applying object: %v", err)
751 }
752 if m := f.ManagedFields(); len(m) < 2 {
753 t.Errorf("expected to start tracking managed fields with at least 2 field managers, but got: %v", m)
754 }
755 if e, a := "test_server_side_apply_without_upgrade", f.ManagedFields()[0].Manager; e != a {
756 t.Fatalf("exected first manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
757 }
758 if e, a := "before-first-apply", f.ManagedFields()[1].Manager; e != a {
759 t.Fatalf("exected second manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
760 }
761
762
763 newObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
764 deployment = []byte(`
765 apiVersion: apps/v1
766 kind: Deployment
767 metadata:
768 name: my-deployment
769 labels:
770 app: my-app-v2 # change
771 spec:
772 replicas: 8 # change
773 `)
774 if err := yaml.Unmarshal(deployment, &newObj.Object); err != nil {
775 t.Errorf("error decoding YAML: %v", err)
776 }
777 if err := f.Apply(newObj, "kubectl", false); err != nil {
778 t.Errorf("error applying object: %v", err)
779 }
780 if m := f.ManagedFields(); len(m) == 0 {
781 t.Errorf("expected to track managed fields, but got: %v", m)
782 }
783 lastApplied, err = getLastApplied(f.Live())
784 if err != nil {
785 t.Errorf("failed to get last applied: %v", err)
786 }
787 if !strings.Contains(lastApplied, "my-app-v2") {
788 t.Errorf("expected last applied annotation to be updated, but got: %q", lastApplied)
789 }
790 }
791
792 func yamlToJSON(y []byte) (string, error) {
793 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
794 if err := yaml.Unmarshal(y, &obj.Object); err != nil {
795 return "", fmt.Errorf("error decoding YAML: %v", err)
796 }
797 serialization, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
798 if err != nil {
799 return "", fmt.Errorf("error encoding object: %v", err)
800 }
801 json, err := yamlutil.ToJSON(serialization)
802 if err != nil {
803 return "", fmt.Errorf("error converting to json: %v", err)
804 }
805 return string(json), nil
806 }
807
808 func setLastAppliedFromEncoded(obj runtime.Object, lastApplied []byte) error {
809 lastAppliedJSON, err := yamlToJSON(lastApplied)
810 if err != nil {
811 return err
812 }
813 return internal.SetLastApplied(obj, lastAppliedJSON)
814 }
815
816 func getLastApplied(obj runtime.Object) (string, error) {
817 accessor := meta.NewAccessor()
818 annotations, err := accessor.Annotations(obj)
819 if err != nil {
820 return "", fmt.Errorf("failed to access annotations: %v", err)
821 }
822 if annotations == nil {
823 return "", fmt.Errorf("no annotations on obj: %v", obj)
824 }
825
826 lastApplied, ok := annotations[internal.LastAppliedConfigAnnotation]
827 if !ok {
828 return "", fmt.Errorf("expected last applied annotation, but got none for object: %v", obj)
829 }
830 return lastApplied, nil
831 }
832
833 func TestUpdateViaSubresources(t *testing.T) {
834 f := managedfieldstest.NewTestFieldManagerSubresource(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"), "scale")
835
836 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
837 if err := yaml.Unmarshal([]byte(`{
838 "apiVersion": "v1",
839 "kind": "Pod",
840 "metadata": {
841 "labels": {
842 "a":"b"
843 },
844 }
845 }`), &obj.Object); err != nil {
846 t.Fatalf("error decoding YAML: %v", err)
847 }
848 obj.SetManagedFields([]metav1.ManagedFieldsEntry{
849 {
850 Manager: "test",
851 Operation: metav1.ManagedFieldsOperationApply,
852 APIVersion: "apps/v1",
853 FieldsType: "FieldsV1",
854 FieldsV1: &metav1.FieldsV1{
855 Raw: []byte(`{"f:metadata":{"f:labels":{"f:another_field":{}}}}`),
856 },
857 },
858 })
859
860
861 expectedManager := "fieldmanager_test_subresource"
862 if err := f.Update(obj, expectedManager); err != nil {
863 t.Fatalf("failed to apply object: %v", err)
864 }
865
866 managedFields := f.ManagedFields()
867 if len(managedFields) != 1 {
868 t.Fatalf("Expected new managed fields to have one entry. Got:\n%#v", managedFields)
869 }
870 if managedFields[0].Manager != expectedManager {
871 t.Fatalf("Expected first item to have manager set to: %s. Got: %s", expectedManager, managedFields[0].Manager)
872 }
873
874
875 newObj := obj.DeepCopy()
876 newObj.SetManagedFields([]metav1.ManagedFieldsEntry{})
877 if err := f.Update(newObj, expectedManager); err != nil {
878 t.Fatalf("failed to apply object: %v", err)
879 }
880 newManagedFields := f.ManagedFields()
881 if len(newManagedFields) != 1 {
882 t.Fatalf("Expected new managed fields to have one entry. Got:\n%#v", newManagedFields)
883 }
884 }
885
886
887 func TestApplyDoesNotChangeManagedFields(t *testing.T) {
888 originalManagedFields := []metav1.ManagedFieldsEntry{}
889 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter,
890 schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
891 newObj := &unstructured.Unstructured{
892 Object: map[string]interface{}{},
893 }
894 appliedObj := &unstructured.Unstructured{
895 Object: map[string]interface{}{},
896 }
897
898
899 if err := yaml.Unmarshal([]byte(`{
900 "apiVersion": "apps/v1",
901 "kind": "Deployment",
902 "metadata": {
903 "name": "deployment",
904 "labels": {"app": "nginx"}
905 },
906 "spec": {
907 "selector": {
908 "matchLabels": {
909 "app": "nginx"
910 }
911 },
912 "template": {
913 "metadata": {
914 "labels": {
915 "app": "nginx"
916 }
917 },
918 "spec": {
919 "containers": [{
920 "name": "nginx",
921 "image": "nginx:latest"
922 }]
923 }
924 }
925 }
926 }`), &newObj.Object); err != nil {
927 t.Fatalf("error decoding YAML: %v", err)
928 }
929
930 if err := yaml.Unmarshal([]byte(`{
931 "apiVersion": "apps/v1",
932 "kind": "Deployment",
933 "metadata": {
934 "name": "deployment",
935 },
936 "spec": {
937 "replicas": 101,
938 }
939 }`), &appliedObj.Object); err != nil {
940 t.Fatalf("error decoding YAML: %v", err)
941 }
942
943
944 if err := f.Apply(newObj.DeepCopyObject(), "fieldmanager_z", false); err != nil {
945 t.Fatalf("failed to apply object: %v", err)
946 }
947
948
949 if err := f.Apply(appliedObj, "fieldmanager_b", false); err != nil {
950 t.Fatalf("failed to apply object %v", err)
951 }
952
953
954
955
956
957
958 for _, field := range f.ManagedFields() {
959 originalManagedFields = append(originalManagedFields, *field.DeepCopy())
960 }
961
962
963 time.Sleep(2 * time.Second)
964
965 if err := f.Apply(newObj, "fieldmanager_z", false); err != nil {
966 t.Fatalf("failed to apply object: %v", err)
967 }
968
969
970 if !reflect.DeepEqual(originalManagedFields, f.ManagedFields()) {
971 originalYAML, _ := yaml.Marshal(originalManagedFields)
972 current, _ := yaml.Marshal(f.ManagedFields())
973
974
975 t.Fatalf("managed fields changed: ORIGINAL\n%v\nCURRENT\n%v",
976 string(originalYAML), string(current))
977 }
978 }
979
980
981 func TestUpdateDoesNotChangeManagedFields(t *testing.T) {
982 originalManagedFields := []metav1.ManagedFieldsEntry{}
983 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter,
984 schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
985 newObj := &unstructured.Unstructured{
986 Object: map[string]interface{}{},
987 }
988
989 if err := yaml.Unmarshal([]byte(`{
990 "apiVersion": "apps/v1",
991 "kind": "Deployment",
992 "metadata": {
993 "name": "deployment",
994 "labels": {"app": "nginx"}
995 },
996 "spec": {
997 "selector": {
998 "matchLabels": {
999 "app": "nginx"
1000 }
1001 },
1002 "template": {
1003 "metadata": {
1004 "labels": {
1005 "app": "nginx"
1006 }
1007 },
1008 "spec": {
1009 "containers": [{
1010 "name": "nginx",
1011 "image": "nginx:latest"
1012 }]
1013 }
1014 }
1015 }
1016 }`), &newObj.Object); err != nil {
1017 t.Fatalf("error decoding YAML: %v", err)
1018 }
1019
1020
1021 if err := f.Update(newObj.DeepCopyObject(), "fieldmanager_z"); err != nil {
1022 t.Fatalf("failed to apply object: %v", err)
1023 }
1024
1025 for _, field := range f.ManagedFields() {
1026 originalManagedFields = append(originalManagedFields, *field.DeepCopy())
1027 }
1028
1029
1030 time.Sleep(2 * time.Second)
1031
1032
1033
1034
1035
1036
1037 if err := f.Update(newObj, "fieldmanager_z"); err != nil {
1038 t.Fatalf("failed to apply object: %v", err)
1039 }
1040
1041
1042 if !reflect.DeepEqual(originalManagedFields, f.ManagedFields()) {
1043 originalYAML, _ := yaml.Marshal(originalManagedFields)
1044 current, _ := yaml.Marshal(f.ManagedFields())
1045
1046
1047 t.Fatalf("managed fields changed: ORIGINAL\n%v\nCURRENT\n%v",
1048 string(originalYAML), string(current))
1049 }
1050 }
1051
1052
1053
1054 func TestLiveObjectManagedFieldsNotRemoved(t *testing.T) {
1055 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter,
1056 schema.FromAPIVersionAndKind("apps/v1", "Deployment"))
1057 newObj := &unstructured.Unstructured{
1058 Object: map[string]interface{}{},
1059 }
1060 appliedObj := &unstructured.Unstructured{
1061 Object: map[string]interface{}{},
1062 }
1063
1064 if err := yaml.Unmarshal([]byte(`{
1065 "apiVersion": "apps/v1",
1066 "kind": "Deployment",
1067 "metadata": {
1068 "name": "deployment",
1069 "labels": {"app": "nginx"}
1070 },
1071 "spec": {
1072 "selector": {
1073 "matchLabels": {
1074 "app": "nginx"
1075 }
1076 },
1077 "template": {
1078 "metadata": {
1079 "labels": {
1080 "app": "nginx"
1081 }
1082 },
1083 "spec": {
1084 "containers": [{
1085 "name": "nginx",
1086 "image": "nginx:latest"
1087 }]
1088 }
1089 }
1090 }
1091 }`), &newObj.Object); err != nil {
1092 t.Fatalf("error decoding YAML: %v", err)
1093 }
1094
1095 if err := yaml.Unmarshal([]byte(`{
1096 "apiVersion": "apps/v1",
1097 "kind": "Deployment",
1098 "metadata": {
1099 "name": "deployment",
1100 },
1101 "spec": {
1102 "replicas": 101,
1103 }
1104 }`), &appliedObj.Object); err != nil {
1105 t.Fatalf("error decoding YAML: %v", err)
1106 }
1107
1108
1109 if err := f.Apply(newObj.DeepCopyObject(), "fieldmanager_z", false); err != nil {
1110 t.Fatalf("failed to apply object: %v", err)
1111 }
1112
1113 originalLiveObj := f.Live()
1114
1115 accessor, err := meta.Accessor(originalLiveObj)
1116 if err != nil {
1117 panic(fmt.Errorf("couldn't get accessor: %v", err))
1118 }
1119
1120
1121 if len(accessor.GetManagedFields()) == 0 {
1122 t.Fatalf("empty managed fields of object which expected nonzero fields")
1123 }
1124
1125
1126 if err := f.Apply(appliedObj.DeepCopyObject(), "fieldmanager_z", false); err != nil {
1127 t.Fatalf("failed to apply object: %v", err)
1128 }
1129
1130 accessor, err = meta.Accessor(originalLiveObj)
1131 if err != nil {
1132 panic(fmt.Errorf("couldn't get accessor: %v", err))
1133 }
1134
1135
1136 if len(accessor.GetManagedFields()) == 0 {
1137 t.Fatalf("empty managed fields of object which expected nonzero fields")
1138 }
1139 }
1140
View as plain text