@@ -406,6 +406,213 @@ var _ = Describe("Controllerutil", func() {
406
406
})
407
407
})
408
408
409
+ Describe ("CreateOrPatch" , func () {
410
+ var deploy * appsv1.Deployment
411
+ var deplSpec appsv1.DeploymentSpec
412
+ var deplKey types.NamespacedName
413
+ var specr controllerutil.MutateFn
414
+
415
+ BeforeEach (func () {
416
+ deploy = & appsv1.Deployment {
417
+ ObjectMeta : metav1.ObjectMeta {
418
+ Name : fmt .Sprintf ("deploy-%d" , rand .Int31 ()),
419
+ Namespace : "default" ,
420
+ },
421
+ }
422
+
423
+ deplSpec = appsv1.DeploymentSpec {
424
+ Selector : & metav1.LabelSelector {
425
+ MatchLabels : map [string ]string {"foo" : "bar" },
426
+ },
427
+ Template : corev1.PodTemplateSpec {
428
+ ObjectMeta : metav1.ObjectMeta {
429
+ Labels : map [string ]string {
430
+ "foo" : "bar" ,
431
+ },
432
+ },
433
+ Spec : corev1.PodSpec {
434
+ Containers : []corev1.Container {
435
+ {
436
+ Name : "busybox" ,
437
+ Image : "busybox" ,
438
+ },
439
+ },
440
+ },
441
+ },
442
+ }
443
+
444
+ deplKey = types.NamespacedName {
445
+ Name : deploy .Name ,
446
+ Namespace : deploy .Namespace ,
447
+ }
448
+
449
+ specr = deploymentSpecr (deploy , deplSpec )
450
+ })
451
+
452
+ assertLocalDeployWasUpdated := func (fetched * appsv1.Deployment ) {
453
+ By ("local deploy object was updated during patch & has same spec, status, resource version as fetched" )
454
+ if fetched == nil {
455
+ fetched = & appsv1.Deployment {}
456
+ ExpectWithOffset (1 , c .Get (context .TODO (), deplKey , fetched )).To (Succeed ())
457
+ }
458
+ ExpectWithOffset (1 , fetched .ResourceVersion ).To (Equal (deploy .ResourceVersion ))
459
+ ExpectWithOffset (1 , fetched .Spec ).To (BeEquivalentTo (deploy .Spec ))
460
+ ExpectWithOffset (1 , fetched .Status ).To (BeEquivalentTo (deploy .Status ))
461
+ }
462
+
463
+ It ("creates a new object if one doesn't exists" , func () {
464
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
465
+
466
+ By ("returning no error" )
467
+ Expect (err ).NotTo (HaveOccurred ())
468
+
469
+ By ("returning OperationResultCreated" )
470
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
471
+
472
+ By ("actually having the deployment created" )
473
+ fetched := & appsv1.Deployment {}
474
+ Expect (c .Get (context .TODO (), deplKey , fetched )).To (Succeed ())
475
+
476
+ By ("being mutated by MutateFn" )
477
+ Expect (fetched .Spec .Template .Spec .Containers ).To (HaveLen (1 ))
478
+ Expect (fetched .Spec .Template .Spec .Containers [0 ].Name ).To (Equal (deplSpec .Template .Spec .Containers [0 ].Name ))
479
+ Expect (fetched .Spec .Template .Spec .Containers [0 ].Image ).To (Equal (deplSpec .Template .Spec .Containers [0 ].Image ))
480
+ })
481
+
482
+ It ("patches existing object" , func () {
483
+ var scale int32 = 2
484
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
485
+ Expect (err ).NotTo (HaveOccurred ())
486
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
487
+
488
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , deploymentScaler (deploy , scale ))
489
+ By ("returning no error" )
490
+ Expect (err ).NotTo (HaveOccurred ())
491
+
492
+ By ("returning OperationResultUpdated" )
493
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultUpdated ))
494
+
495
+ By ("actually having the deployment scaled" )
496
+ fetched := & appsv1.Deployment {}
497
+ Expect (c .Get (context .TODO (), deplKey , fetched )).To (Succeed ())
498
+ Expect (* fetched .Spec .Replicas ).To (Equal (scale ))
499
+ assertLocalDeployWasUpdated (fetched )
500
+ })
501
+
502
+ It ("patches only changed objects" , func () {
503
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
504
+
505
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
506
+ Expect (err ).NotTo (HaveOccurred ())
507
+
508
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , deploymentIdentity )
509
+ By ("returning no error" )
510
+ Expect (err ).NotTo (HaveOccurred ())
511
+
512
+ By ("returning OperationResultNone" )
513
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultNone ))
514
+
515
+ assertLocalDeployWasUpdated (nil )
516
+ })
517
+
518
+ It ("patches only changed status" , func () {
519
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
520
+
521
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
522
+ Expect (err ).NotTo (HaveOccurred ())
523
+
524
+ deployStatus := appsv1.DeploymentStatus {
525
+ ReadyReplicas : 1 ,
526
+ Replicas : 3 ,
527
+ }
528
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , deploymentStatusr (deploy , deployStatus ))
529
+ By ("returning no error" )
530
+ Expect (err ).NotTo (HaveOccurred ())
531
+
532
+ By ("returning OperationResultUpdatedStatusOnly" )
533
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultUpdatedStatusOnly ))
534
+
535
+ assertLocalDeployWasUpdated (nil )
536
+ })
537
+
538
+ It ("patches resource and status" , func () {
539
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
540
+
541
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
542
+ Expect (err ).NotTo (HaveOccurred ())
543
+
544
+ replicas := int32 (3 )
545
+ deployStatus := appsv1.DeploymentStatus {
546
+ ReadyReplicas : 1 ,
547
+ Replicas : replicas ,
548
+ }
549
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , func () error {
550
+ Expect (deploymentScaler (deploy , replicas )()).To (Succeed ())
551
+ return deploymentStatusr (deploy , deployStatus )()
552
+ })
553
+ By ("returning no error" )
554
+ Expect (err ).NotTo (HaveOccurred ())
555
+
556
+ By ("returning OperationResultUpdatedStatus" )
557
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultUpdatedStatus ))
558
+
559
+ assertLocalDeployWasUpdated (nil )
560
+ })
561
+
562
+ It ("errors when MutateFn changes object name on creation" , func () {
563
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , func () error {
564
+ Expect (specr ()).To (Succeed ())
565
+ return deploymentRenamer (deploy )()
566
+ })
567
+
568
+ By ("returning error" )
569
+ Expect (err ).To (HaveOccurred ())
570
+
571
+ By ("returning OperationResultNone" )
572
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultNone ))
573
+ })
574
+
575
+ It ("errors when MutateFn renames an object" , func () {
576
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
577
+
578
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
579
+ Expect (err ).NotTo (HaveOccurred ())
580
+
581
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , deploymentRenamer (deploy ))
582
+
583
+ By ("returning error" )
584
+ Expect (err ).To (HaveOccurred ())
585
+
586
+ By ("returning OperationResultNone" )
587
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultNone ))
588
+ })
589
+
590
+ It ("errors when object namespace changes" , func () {
591
+ op , err := controllerutil .CreateOrPatch (context .TODO (), c , deploy , specr )
592
+
593
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultCreated ))
594
+ Expect (err ).NotTo (HaveOccurred ())
595
+
596
+ op , err = controllerutil .CreateOrPatch (context .TODO (), c , deploy , deploymentNamespaceChanger (deploy ))
597
+
598
+ By ("returning error" )
599
+ Expect (err ).To (HaveOccurred ())
600
+
601
+ By ("returning OperationResultNone" )
602
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultNone ))
603
+ })
604
+
605
+ It ("aborts immediately if there was an error initially retrieving the object" , func () {
606
+ op , err := controllerutil .CreateOrPatch (context .TODO (), errorReader {c }, deploy , func () error {
607
+ Fail ("Mutation method should not run" )
608
+ return nil
609
+ })
610
+
611
+ Expect (op ).To (BeEquivalentTo (controllerutil .OperationResultNone ))
612
+ Expect (err ).To (HaveOccurred ())
613
+ })
614
+ })
615
+
409
616
Describe ("Finalizers" , func () {
410
617
var deploy * appsv1.Deployment
411
618
@@ -478,6 +685,13 @@ func deploymentSpecr(deploy *appsv1.Deployment, spec appsv1.DeploymentSpec) cont
478
685
}
479
686
}
480
687
688
+ func deploymentStatusr (deploy * appsv1.Deployment , status appsv1.DeploymentStatus ) controllerutil.MutateFn {
689
+ return func () error {
690
+ deploy .Status = status
691
+ return nil
692
+ }
693
+ }
694
+
481
695
var deploymentIdentity controllerutil.MutateFn = func () error {
482
696
return nil
483
697
}
0 commit comments