@@ -7,6 +7,10 @@ import (
7
7
"reflect"
8
8
"testing"
9
9
10
+ corelisterv1 "k8s.io/client-go/listers/core/v1"
11
+ clientgotesting "k8s.io/client-go/testing"
12
+ "k8s.io/client-go/tools/cache"
13
+
10
14
corev1 "k8s.io/api/core/v1"
11
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12
16
"k8s.io/apimachinery/pkg/labels"
@@ -20,6 +24,7 @@ import (
20
24
cov1helpers "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers"
21
25
mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1"
22
26
ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common"
27
+ "github.com/openshift/machine-config-operator/test/helpers"
23
28
)
24
29
25
30
func TestIsMachineConfigPoolConfigurationValid (t * testing.T ) {
@@ -152,12 +157,23 @@ func TestIsMachineConfigPoolConfigurationValid(t *testing.T) {
152
157
}
153
158
}
154
159
155
- type mockMCPLister struct {}
160
+ type mockMCPLister struct {
161
+ pools []* mcfgv1.MachineConfigPool
162
+ }
156
163
157
164
func (mcpl * mockMCPLister ) List (selector labels.Selector ) (ret []* mcfgv1.MachineConfigPool , err error ) {
158
- return nil , nil
165
+ return mcpl . pools , nil
159
166
}
160
167
func (mcpl * mockMCPLister ) Get (name string ) (ret * mcfgv1.MachineConfigPool , err error ) {
168
+ if mcpl .pools == nil {
169
+ return nil , nil
170
+ }
171
+ for _ , pool := range mcpl .pools {
172
+ if pool .Name == name {
173
+ return pool , nil
174
+ }
175
+
176
+ }
161
177
return nil , nil
162
178
}
163
179
@@ -550,7 +566,24 @@ func TestOperatorSyncStatus(t *testing.T) {
550
566
eventRecorder : & record.FakeRecorder {},
551
567
}
552
568
optr .vStore = newVersionStore ()
553
- optr .mcpLister = & mockMCPLister {}
569
+ optr .mcpLister = & mockMCPLister {
570
+ pools : []* mcfgv1.MachineConfigPool {
571
+ helpers .NewMachineConfigPool ("master" , nil , helpers .MasterSelector , "v0" ),
572
+ helpers .NewMachineConfigPool ("workers" , nil , helpers .WorkerSelector , "v0" ),
573
+ },
574
+ }
575
+
576
+ nodeIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
577
+ optr .nodeLister = corelisterv1 .NewNodeLister (nodeIndexer )
578
+ nodeIndexer .Add (& corev1.Node {
579
+ ObjectMeta : metav1.ObjectMeta {Name : "first-node" , Labels : map [string ]string {"node-role/worker" : "" }},
580
+ Status : corev1.NodeStatus {
581
+ NodeInfo : corev1.NodeSystemInfo {
582
+ KubeletVersion : "v1.21" ,
583
+ },
584
+ },
585
+ })
586
+
554
587
coName := fmt .Sprintf ("test-%s" , uuid .NewUUID ())
555
588
co := & configv1.ClusterOperator {ObjectMeta : metav1.ObjectMeta {Name : coName }}
556
589
cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorAvailable , Status : configv1 .ConditionFalse })
@@ -559,6 +592,14 @@ func TestOperatorSyncStatus(t *testing.T) {
559
592
cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorUpgradeable , Status : configv1 .ConditionUnknown })
560
593
co .Status .Versions = append (co .Status .Versions , configv1.OperandVersion {Name : "operator" , Version : "test-version" })
561
594
optr .name = coName
595
+ kasOperator := & configv1.ClusterOperator {
596
+ ObjectMeta : metav1.ObjectMeta {Name : "kube-apiserver" },
597
+ Status : configv1.ClusterOperatorStatus {
598
+ Versions : []configv1.OperandVersion {
599
+ {Name : "kube-apiserver" , Version : "1.21" },
600
+ },
601
+ },
602
+ }
562
603
563
604
for j , sync := range testCase .syncs {
564
605
optr .inClusterBringup = sync .inClusterBringUp
@@ -567,7 +608,7 @@ func TestOperatorSyncStatus(t *testing.T) {
567
608
} else {
568
609
optr .vStore .Set ("operator" , "test-version" )
569
610
}
570
- optr .configClient = fakeconfigclientset .NewSimpleClientset (co )
611
+ optr .configClient = fakeconfigclientset .NewSimpleClientset (co , kasOperator )
571
612
err := optr .syncAll (sync .syncFuncs )
572
613
if sync .expectOperatorFail {
573
614
assert .NotNil (t , err , "test case %d, sync call %d, expected an error" , idx , j )
@@ -597,12 +638,179 @@ func TestInClusterBringUpStayOnErr(t *testing.T) {
597
638
}
598
639
optr .vStore = newVersionStore ()
599
640
optr .vStore .Set ("operator" , "test-version" )
600
- optr .mcpLister = & mockMCPLister {}
641
+ optr .mcpLister = & mockMCPLister {
642
+ pools : []* mcfgv1.MachineConfigPool {
643
+ helpers .NewMachineConfigPool ("master" , nil , helpers .MasterSelector , "v0" ),
644
+ helpers .NewMachineConfigPool ("workers" , nil , helpers .WorkerSelector , "v0" ),
645
+ },
646
+ }
647
+ nodeIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
648
+ optr .nodeLister = corelisterv1 .NewNodeLister (nodeIndexer )
649
+ nodeIndexer .Add (& corev1.Node {
650
+ ObjectMeta : metav1.ObjectMeta {Name : "first-node" , Labels : map [string ]string {"node-role/worker" : "" }},
651
+ Status : corev1.NodeStatus {
652
+ NodeInfo : corev1.NodeSystemInfo {
653
+ KubeletVersion : "v1.21" ,
654
+ },
655
+ },
656
+ })
657
+ co := & configv1.ClusterOperator {}
658
+ kasOperator := & configv1.ClusterOperator {
659
+ ObjectMeta : metav1.ObjectMeta {Name : "kube-apiserver" },
660
+ Status : configv1.ClusterOperatorStatus {
661
+ Versions : []configv1.OperandVersion {
662
+ {Name : "kube-apiserver" , Version : "1.21" },
663
+ },
664
+ },
665
+ }
666
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorAvailable , Status : configv1 .ConditionFalse })
667
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorProgressing , Status : configv1 .ConditionFalse })
668
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorDegraded , Status : configv1 .ConditionFalse })
669
+ optr .configClient = fakeconfigclientset .NewSimpleClientset (co , kasOperator )
670
+ optr .inClusterBringup = true
671
+
672
+ fn1 := func (config * renderConfig ) error {
673
+ return errors .New ("mocked fn1" )
674
+ }
675
+ err := optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
676
+ assert .NotNil (t , err , "expected syncAll to fail" )
677
+
678
+ assert .True (t , optr .inClusterBringup )
679
+
680
+ fn1 = func (config * renderConfig ) error {
681
+ return nil
682
+ }
683
+ err = optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
684
+ assert .Nil (t , err , "expected syncAll to pass" )
685
+
686
+ assert .False (t , optr .inClusterBringup )
687
+ }
688
+
689
+ func TestKubeletSkewUnSupported (t * testing.T ) {
690
+ kasOperator := & configv1.ClusterOperator {
691
+ ObjectMeta : metav1.ObjectMeta {Name : "kube-apiserver" },
692
+ Status : configv1.ClusterOperatorStatus {
693
+ Versions : []configv1.OperandVersion {
694
+ {Name : "kube-apiserver" , Version : "1.21" },
695
+ },
696
+ },
697
+ }
698
+ optr := & Operator {
699
+ eventRecorder : & record.FakeRecorder {},
700
+ }
701
+ optr .vStore = newVersionStore ()
702
+ optr .vStore .Set ("operator" , "test-version" )
703
+ optr .mcpLister = & mockMCPLister {
704
+ pools : []* mcfgv1.MachineConfigPool {
705
+ helpers .NewMachineConfigPool ("master" , nil , helpers .MasterSelector , "v0" ),
706
+ helpers .NewMachineConfigPool ("workers" , nil , helpers .WorkerSelector , "v0" ),
707
+ },
708
+ }
709
+ nodeIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
710
+ optr .nodeLister = corelisterv1 .NewNodeLister (nodeIndexer )
711
+ nodeIndexer .Add (& corev1.Node {
712
+ ObjectMeta : metav1.ObjectMeta {Name : "first-node" , Labels : map [string ]string {"node-role/worker" : "" }},
713
+ Status : corev1.NodeStatus {
714
+ NodeInfo : corev1.NodeSystemInfo {
715
+ KubeletVersion : "v1.18" ,
716
+ },
717
+ },
718
+ })
719
+
720
+ co := & configv1.ClusterOperator {}
721
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorAvailable , Status : configv1 .ConditionFalse })
722
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorProgressing , Status : configv1 .ConditionFalse })
723
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorDegraded , Status : configv1 .ConditionFalse })
724
+ fakeClient := fakeconfigclientset .NewSimpleClientset (co , kasOperator )
725
+ optr .configClient = fakeClient
726
+ optr .inClusterBringup = true
727
+
728
+ fn1 := func (config * renderConfig ) error {
729
+ return errors .New ("mocked fn1" )
730
+ }
731
+ err := optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
732
+ assert .NotNil (t , err , "expected syncAll to fail" )
733
+
734
+ assert .True (t , optr .inClusterBringup )
735
+
736
+ fn1 = func (config * renderConfig ) error {
737
+ return nil
738
+ }
739
+ err = optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
740
+ assert .Nil (t , err , "expected syncAll to pass" )
741
+
742
+ assert .False (t , optr .inClusterBringup )
743
+
744
+ var lastUpdate clientgotesting.UpdateAction
745
+ for _ , action := range fakeClient .Actions () {
746
+ if action .GetVerb () == "update" {
747
+ lastUpdate = action .(clientgotesting.UpdateAction )
748
+ }
749
+ }
750
+ if lastUpdate == nil {
751
+ t .Fatal ("missing update" )
752
+ }
753
+ operatorStatus := lastUpdate .GetObject ().(* configv1.ClusterOperator )
754
+ var upgradeable * configv1.ClusterOperatorStatusCondition
755
+ for _ , condition := range operatorStatus .Status .Conditions {
756
+ if condition .Type == configv1 .OperatorUpgradeable {
757
+ upgradeable = & condition
758
+ break
759
+ }
760
+ }
761
+ if upgradeable == nil {
762
+ t .Fatal ("missing condition" )
763
+ }
764
+ if upgradeable .Status != configv1 .ConditionTrue {
765
+ t .Fatal (upgradeable )
766
+ }
767
+ if upgradeable .Message != "One or more nodes have an unsupported kubelet version skew. Please see `oc get nodes` for details and upgrade all nodes so that they have a kubelet version of at least 1.19." {
768
+ t .Fatal (upgradeable )
769
+ }
770
+ if upgradeable .Reason != "KubeletSkewUnsupported" {
771
+ t .Fatal (upgradeable )
772
+ }
773
+ }
774
+
775
+ func TestCustomPoolKubeletSkewUnSupported (t * testing.T ) {
776
+ customSelector := metav1 .AddLabelToSelector (& metav1.LabelSelector {}, "node-role/custom" , "" )
777
+ kasOperator := & configv1.ClusterOperator {
778
+ ObjectMeta : metav1.ObjectMeta {Name : "kube-apiserver" },
779
+ Status : configv1.ClusterOperatorStatus {
780
+ Versions : []configv1.OperandVersion {
781
+ {Name : "kube-apiserver" , Version : "1.21" },
782
+ },
783
+ },
784
+ }
785
+ optr := & Operator {
786
+ eventRecorder : & record.FakeRecorder {},
787
+ }
788
+ optr .vStore = newVersionStore ()
789
+ optr .vStore .Set ("operator" , "test-version" )
790
+ optr .mcpLister = & mockMCPLister {
791
+ pools : []* mcfgv1.MachineConfigPool {
792
+ helpers .NewMachineConfigPool ("master" , nil , helpers .MasterSelector , "v0" ),
793
+ helpers .NewMachineConfigPool ("workers" , nil , helpers .WorkerSelector , "v0" ),
794
+ helpers .NewMachineConfigPool ("custom" , nil , customSelector , "v0" ),
795
+ },
796
+ }
797
+ nodeIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
798
+ optr .nodeLister = corelisterv1 .NewNodeLister (nodeIndexer )
799
+ nodeIndexer .Add (& corev1.Node {
800
+ ObjectMeta : metav1.ObjectMeta {Name : "custom" , Labels : map [string ]string {"node-role/custom" : "" }},
801
+ Status : corev1.NodeStatus {
802
+ NodeInfo : corev1.NodeSystemInfo {
803
+ KubeletVersion : "v1.18" ,
804
+ },
805
+ },
806
+ })
807
+
601
808
co := & configv1.ClusterOperator {}
602
809
cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorAvailable , Status : configv1 .ConditionFalse })
603
810
cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorProgressing , Status : configv1 .ConditionFalse })
604
811
cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorDegraded , Status : configv1 .ConditionFalse })
605
- optr .configClient = fakeconfigclientset .NewSimpleClientset (co )
812
+ fakeClient := fakeconfigclientset .NewSimpleClientset (co , kasOperator )
813
+ optr .configClient = fakeClient
606
814
optr .inClusterBringup = true
607
815
608
816
fn1 := func (config * renderConfig ) error {
@@ -620,4 +828,156 @@ func TestInClusterBringUpStayOnErr(t *testing.T) {
620
828
assert .Nil (t , err , "expected syncAll to pass" )
621
829
622
830
assert .False (t , optr .inClusterBringup )
831
+
832
+ var lastUpdate clientgotesting.UpdateAction
833
+ for _ , action := range fakeClient .Actions () {
834
+ if action .GetVerb () == "update" {
835
+ lastUpdate = action .(clientgotesting.UpdateAction )
836
+ }
837
+ }
838
+ if lastUpdate == nil {
839
+ t .Fatal ("missing update" )
840
+ }
841
+ operatorStatus := lastUpdate .GetObject ().(* configv1.ClusterOperator )
842
+ var upgradeable * configv1.ClusterOperatorStatusCondition
843
+ for _ , condition := range operatorStatus .Status .Conditions {
844
+ if condition .Type == configv1 .OperatorUpgradeable {
845
+ upgradeable = & condition
846
+ break
847
+ }
848
+ }
849
+ if upgradeable == nil {
850
+ t .Fatal ("missing condition" )
851
+ }
852
+ if upgradeable .Status != configv1 .ConditionTrue {
853
+ t .Fatal (upgradeable )
854
+ }
855
+ if upgradeable .Message != "One or more nodes have an unsupported kubelet version skew. Please see `oc get nodes` for details and upgrade all nodes so that they have a kubelet version of at least 1.19." {
856
+ t .Fatal (upgradeable )
857
+ }
858
+ if upgradeable .Reason != "KubeletSkewUnsupported" {
859
+ t .Fatal (upgradeable )
860
+ }
861
+ }
862
+
863
+ func TestKubeletSkewSupported (t * testing.T ) {
864
+ kasOperator := & configv1.ClusterOperator {
865
+ ObjectMeta : metav1.ObjectMeta {Name : "kube-apiserver" },
866
+ Status : configv1.ClusterOperatorStatus {
867
+ Versions : []configv1.OperandVersion {
868
+ {Name : "kube-apiserver" , Version : "1.21" },
869
+ },
870
+ },
871
+ }
872
+ optr := & Operator {
873
+ eventRecorder : & record.FakeRecorder {},
874
+ }
875
+ optr .vStore = newVersionStore ()
876
+ optr .vStore .Set ("operator" , "test-version" )
877
+ optr .mcpLister = & mockMCPLister {
878
+ pools : []* mcfgv1.MachineConfigPool {
879
+ helpers .NewMachineConfigPool ("master" , nil , helpers .MasterSelector , "v0" ),
880
+ helpers .NewMachineConfigPool ("workers" , nil , helpers .WorkerSelector , "v0" ),
881
+ },
882
+ }
883
+ nodeIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
884
+ optr .nodeLister = corelisterv1 .NewNodeLister (nodeIndexer )
885
+ nodeIndexer .Add (& corev1.Node {
886
+ ObjectMeta : metav1.ObjectMeta {Name : "first-node" , Labels : map [string ]string {"node-role/worker" : "" }},
887
+ Status : corev1.NodeStatus {
888
+ NodeInfo : corev1.NodeSystemInfo {
889
+ KubeletVersion : "v1.20" ,
890
+ },
891
+ },
892
+ })
893
+
894
+ co := & configv1.ClusterOperator {}
895
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorAvailable , Status : configv1 .ConditionFalse })
896
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorProgressing , Status : configv1 .ConditionFalse })
897
+ cov1helpers .SetStatusCondition (& co .Status .Conditions , configv1.ClusterOperatorStatusCondition {Type : configv1 .OperatorDegraded , Status : configv1 .ConditionFalse })
898
+ fakeClient := fakeconfigclientset .NewSimpleClientset (co , kasOperator )
899
+ optr .configClient = fakeClient
900
+ optr .inClusterBringup = true
901
+
902
+ fn1 := func (config * renderConfig ) error {
903
+ return errors .New ("mocked fn1" )
904
+ }
905
+ err := optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
906
+ assert .NotNil (t , err , "expected syncAll to fail" )
907
+
908
+ assert .True (t , optr .inClusterBringup )
909
+
910
+ fn1 = func (config * renderConfig ) error {
911
+ return nil
912
+ }
913
+ err = optr .syncAll ([]syncFunc {{name : "mock1" , fn : fn1 }})
914
+ assert .Nil (t , err , "expected syncAll to pass" )
915
+
916
+ assert .False (t , optr .inClusterBringup )
917
+
918
+ var lastUpdate clientgotesting.UpdateAction
919
+ for _ , action := range fakeClient .Actions () {
920
+ if action .GetVerb () == "update" {
921
+ lastUpdate = action .(clientgotesting.UpdateAction )
922
+ }
923
+ }
924
+ if lastUpdate == nil {
925
+ t .Fatal ("missing update" )
926
+ }
927
+ operatorStatus := lastUpdate .GetObject ().(* configv1.ClusterOperator )
928
+ var upgradeable * configv1.ClusterOperatorStatusCondition
929
+ for _ , condition := range operatorStatus .Status .Conditions {
930
+ if condition .Type == configv1 .OperatorUpgradeable {
931
+ upgradeable = & condition
932
+ break
933
+ }
934
+ }
935
+ if upgradeable == nil {
936
+ t .Fatal ("missing condition" )
937
+ }
938
+ if upgradeable .Status != configv1 .ConditionTrue {
939
+ t .Fatal (upgradeable )
940
+ }
941
+ if upgradeable .Message != "" {
942
+ t .Fatal (upgradeable )
943
+ }
944
+ if upgradeable .Reason != "AsExpected" {
945
+ t .Fatal (upgradeable )
946
+ }
947
+ }
948
+
949
+ func TestGetMinorKubeletVersion (t * testing.T ) {
950
+ tcs := []struct {
951
+ version string
952
+ minor int
953
+ expectNilErr bool
954
+ }{
955
+ {"v1.20.1" , 20 , true },
956
+ {"v1.20.1+abc0" , 20 , true },
957
+ {"v1.20.1+0123" , 20 , true },
958
+ {"v1.20.1-rc" , 20 , true },
959
+ {"v1.20.1-rc.1" , 20 , true },
960
+ {"v1.20.1-rc+abc123" , 20 , true },
961
+ {"v1.20.1-rc.0+abc123" , 20 , true },
962
+ {"v1.20.1" , 20 , true },
963
+ {"1.20.1" , 20 , true },
964
+ {"1.20" , 20 , true },
965
+ {"12" , 0 , false },
966
+ {".xy" , 0 , false },
967
+ {"1.xy.1" , 0 , false },
968
+ }
969
+ for _ , tc := range tcs {
970
+ minorV , err := getMinorKubeletVersion (tc .version )
971
+ if tc .expectNilErr && err != nil {
972
+ t .Errorf ("test %q failed: unexpected error %v" , tc .version , err )
973
+ continue
974
+ }
975
+ if ! tc .expectNilErr && err == nil {
976
+ t .Errorf ("test %q failed: expected error, got nil " , tc .version )
977
+ continue
978
+ }
979
+ if tc .expectNilErr {
980
+ assert .Equal (t , tc .minor , minorV , fmt .Sprintf ("failed test %q" , tc .version ))
981
+ }
982
+ }
623
983
}
0 commit comments