@@ -23,8 +23,10 @@ import (
2323 configv1 "github.com/openshift/api/config/v1"
2424 features "github.com/openshift/api/features"
2525 mcfgv1 "github.com/openshift/api/machineconfiguration/v1"
26+ opv1 "github.com/openshift/api/operator/v1"
2627 fakeconfigclientset "github.com/openshift/client-go/config/clientset/versioned/fake"
2728 configlistersv1 "github.com/openshift/client-go/config/listers/config/v1"
29+ mcoplistersv1 "github.com/openshift/client-go/operator/listers/operator/v1"
2830 cov1helpers "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers"
2931 ctrlcommon "github.com/openshift/machine-config-operator/pkg/controller/common"
3032 "github.com/openshift/machine-config-operator/test/helpers"
@@ -795,3 +797,378 @@ func TestInClusterBringUpStayOnErr(t *testing.T) {
795797
796798 assert .False (t , optr .inClusterBringup )
797799}
800+
801+ func TestCheckBootImageSkewUpgradeableGuard (t * testing.T ) {
802+ tests := []struct {
803+ name string
804+ featureGateEnabled bool
805+ mcop * opv1.MachineConfiguration
806+ mcopNotFound bool
807+ mcopGetError error
808+ expectUpgradeBlock bool
809+ expectMessage string
810+ expectError bool
811+ }{
812+ {
813+ name : "feature gate disabled" ,
814+ featureGateEnabled : false ,
815+ mcop : nil ,
816+ expectUpgradeBlock : false ,
817+ expectMessage : "" ,
818+ expectError : false ,
819+ },
820+ {
821+ name : "MachineConfiguration not found" ,
822+ featureGateEnabled : true ,
823+ mcopNotFound : true ,
824+ expectUpgradeBlock : false ,
825+ expectMessage : "" ,
826+ expectError : false ,
827+ },
828+ {
829+ name : "mode is None" ,
830+ featureGateEnabled : true ,
831+ mcop : & opv1.MachineConfiguration {
832+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
833+ Status : opv1.MachineConfigurationStatus {
834+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
835+ Mode : opv1 .BootImageSkewEnforcementModeStatusNone ,
836+ },
837+ },
838+ },
839+ expectUpgradeBlock : false ,
840+ expectMessage : "" ,
841+ expectError : false ,
842+ },
843+ {
844+ name : "mode is unset" ,
845+ featureGateEnabled : true ,
846+ mcop : & opv1.MachineConfiguration {
847+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
848+ Status : opv1.MachineConfigurationStatus {
849+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
850+ Mode : "" ,
851+ },
852+ },
853+ },
854+ expectUpgradeBlock : false ,
855+ expectMessage : "" ,
856+ expectError : false ,
857+ },
858+ // OCP version tests in automatic mode
859+ {
860+ name : "mode is Automatic with OCP version within limit" ,
861+ featureGateEnabled : true ,
862+ mcop : & opv1.MachineConfiguration {
863+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
864+ Status : opv1.MachineConfigurationStatus {
865+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
866+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
867+ Automatic : opv1.ClusterBootImageAutomatic {
868+ OCPVersion : "4.17.0" ,
869+ },
870+ },
871+ },
872+ },
873+ expectUpgradeBlock : false ,
874+ expectMessage : "" ,
875+ expectError : false ,
876+ },
877+ {
878+ name : "mode is Automatic with OCP version below limit" ,
879+ featureGateEnabled : true ,
880+ mcop : & opv1.MachineConfiguration {
881+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
882+ Status : opv1.MachineConfigurationStatus {
883+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
884+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
885+ Automatic : opv1.ClusterBootImageAutomatic {
886+ OCPVersion : "4.12.0" ,
887+ },
888+ },
889+ },
890+ },
891+ expectUpgradeBlock : true ,
892+ expectMessage : "Upgrades have been disabled because the cluster is using OCP boot image version 4.12.0, which is below the minimum required version " + ctrlcommon .OCPVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
893+ expectError : false ,
894+ },
895+ // OCP version tests in manual mode
896+ {
897+ name : "mode is Manual with OCP version within limit" ,
898+ featureGateEnabled : true ,
899+ mcop : & opv1.MachineConfiguration {
900+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
901+ Status : opv1.MachineConfigurationStatus {
902+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
903+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
904+ Manual : opv1.ClusterBootImageManual {
905+ Mode : opv1 .ClusterBootImageSpecModeOCPVersion ,
906+ OCPVersion : "4.16.0" ,
907+ },
908+ },
909+ },
910+ },
911+ expectUpgradeBlock : false ,
912+ expectMessage : "" ,
913+ expectError : false ,
914+ },
915+ {
916+ name : "mode is Manual with OCP version below limit" ,
917+ featureGateEnabled : true ,
918+ mcop : & opv1.MachineConfiguration {
919+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
920+ Status : opv1.MachineConfigurationStatus {
921+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
922+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
923+ Manual : opv1.ClusterBootImageManual {
924+ Mode : opv1 .ClusterBootImageSpecModeOCPVersion ,
925+ OCPVersion : "4.10.0" ,
926+ },
927+ },
928+ },
929+ },
930+ expectUpgradeBlock : true ,
931+ expectMessage : "Upgrades have been disabled because the cluster is using OCP boot image version 4.10.0, which is below the minimum required version " + ctrlcommon .OCPVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
932+ expectError : false ,
933+ },
934+ {
935+ name : "mode is Automatic with exact minimum OCP version" ,
936+ featureGateEnabled : true ,
937+ mcop : & opv1.MachineConfiguration {
938+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
939+ Status : opv1.MachineConfigurationStatus {
940+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
941+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
942+ Automatic : opv1.ClusterBootImageAutomatic {
943+ OCPVersion : ctrlcommon .OCPVersionBootImageSkewLimit ,
944+ },
945+ },
946+ },
947+ },
948+ expectUpgradeBlock : false ,
949+ expectMessage : "" ,
950+ expectError : false ,
951+ },
952+ // RHCOS version tests in Automatic mode
953+ {
954+ name : "mode is Automatic with modern RHCOS version within limit" ,
955+ featureGateEnabled : true ,
956+ mcop : & opv1.MachineConfiguration {
957+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
958+ Status : opv1.MachineConfigurationStatus {
959+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
960+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
961+ Automatic : opv1.ClusterBootImageAutomatic {
962+ RHCOSVersion : "9.4.20251023-0" ,
963+ },
964+ },
965+ },
966+ },
967+ expectUpgradeBlock : false ,
968+ expectMessage : "" ,
969+ expectError : false ,
970+ },
971+ {
972+ name : "mode is Automatic with modern RHCOS version below limit" ,
973+ featureGateEnabled : true ,
974+ mcop : & opv1.MachineConfiguration {
975+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
976+ Status : opv1.MachineConfigurationStatus {
977+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
978+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
979+ Automatic : opv1.ClusterBootImageAutomatic {
980+ RHCOSVersion : "9.0.20251023-0" ,
981+ },
982+ },
983+ },
984+ },
985+ expectUpgradeBlock : true ,
986+ expectMessage : "Upgrades have been disabled because the cluster is using RHCOS boot image version 9.0.20251023-0(RHEL version: 9.0), which is below the minimum required RHEL version " + ctrlcommon .RHCOSVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
987+ expectError : false ,
988+ },
989+ {
990+ name : "mode is Automatic with legacy RHCOS version within limit" ,
991+ featureGateEnabled : true ,
992+ mcop : & opv1.MachineConfiguration {
993+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
994+ Status : opv1.MachineConfigurationStatus {
995+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
996+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
997+ Automatic : opv1.ClusterBootImageAutomatic {
998+ RHCOSVersion : "416.94.202510081640-0" ,
999+ },
1000+ },
1001+ },
1002+ },
1003+ expectUpgradeBlock : false ,
1004+ expectMessage : "" ,
1005+ expectError : false ,
1006+ },
1007+ {
1008+ name : "mode is Automatic with legacy RHCOS version below limit" ,
1009+ featureGateEnabled : true ,
1010+ mcop : & opv1.MachineConfiguration {
1011+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1012+ Status : opv1.MachineConfigurationStatus {
1013+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1014+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
1015+ Automatic : opv1.ClusterBootImageAutomatic {
1016+ RHCOSVersion : "411.86.202308081056-0" ,
1017+ },
1018+ },
1019+ },
1020+ },
1021+ expectUpgradeBlock : true ,
1022+ expectMessage : "Upgrades have been disabled because the cluster is using RHCOS boot image version 411.86.202308081056-0(RHEL version: 8.6), which is below the minimum required RHEL version " + ctrlcommon .RHCOSVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
1023+ expectError : false ,
1024+ },
1025+
1026+ {
1027+ name : "mode is Automatic with exact minimum RHCOS version" ,
1028+ featureGateEnabled : true ,
1029+ mcop : & opv1.MachineConfiguration {
1030+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1031+ Status : opv1.MachineConfigurationStatus {
1032+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1033+ Mode : opv1 .BootImageSkewEnforcementModeStatusAutomatic ,
1034+ Automatic : opv1.ClusterBootImageAutomatic {
1035+ RHCOSVersion : "413.92.202402131523-0" ,
1036+ },
1037+ },
1038+ },
1039+ },
1040+ expectUpgradeBlock : false ,
1041+ expectMessage : "" ,
1042+ expectError : false ,
1043+ },
1044+ // RHCOS version tests in manual mode
1045+ {
1046+ name : "mode is Manual with modern RHCOS version within limit" ,
1047+ featureGateEnabled : true ,
1048+ mcop : & opv1.MachineConfiguration {
1049+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1050+ Status : opv1.MachineConfigurationStatus {
1051+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1052+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
1053+ Manual : opv1.ClusterBootImageManual {
1054+ Mode : opv1 .ClusterBootImageSpecModeRHCOSVersion ,
1055+ RHCOSVersion : "9.6.20251023-0" ,
1056+ },
1057+ },
1058+ },
1059+ },
1060+ expectUpgradeBlock : false ,
1061+ expectMessage : "" ,
1062+ expectError : false ,
1063+ },
1064+ {
1065+ name : "mode is Manual with modern RHCOS version below limit" ,
1066+ featureGateEnabled : true ,
1067+ mcop : & opv1.MachineConfiguration {
1068+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1069+ Status : opv1.MachineConfigurationStatus {
1070+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1071+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
1072+ Manual : opv1.ClusterBootImageManual {
1073+ Mode : opv1 .ClusterBootImageSpecModeRHCOSVersion ,
1074+ RHCOSVersion : "9.1.20251023-0" ,
1075+ },
1076+ },
1077+ },
1078+ },
1079+ expectUpgradeBlock : true ,
1080+ expectMessage : "Upgrades have been disabled because the cluster is using RHCOS boot image version 9.1.20251023-0(RHEL version: 9.1), which is below the minimum required RHEL version " + ctrlcommon .RHCOSVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
1081+ expectError : false ,
1082+ },
1083+ {
1084+ name : "mode is Manual with legacy RHCOS version within limit" ,
1085+ featureGateEnabled : true ,
1086+ mcop : & opv1.MachineConfiguration {
1087+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1088+ Status : opv1.MachineConfigurationStatus {
1089+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1090+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
1091+ Manual : opv1.ClusterBootImageManual {
1092+ Mode : opv1 .ClusterBootImageSpecModeRHCOSVersion ,
1093+ RHCOSVersion : "416.94.202510081640-0" ,
1094+ },
1095+ },
1096+ },
1097+ },
1098+ expectUpgradeBlock : false ,
1099+ expectMessage : "" ,
1100+ expectError : false ,
1101+ },
1102+ {
1103+ name : "mode is Manual with legacy RHCOS version below limit" ,
1104+ featureGateEnabled : true ,
1105+ mcop : & opv1.MachineConfiguration {
1106+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1107+ Status : opv1.MachineConfigurationStatus {
1108+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1109+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
1110+ Manual : opv1.ClusterBootImageManual {
1111+ Mode : opv1 .ClusterBootImageSpecModeRHCOSVersion ,
1112+ RHCOSVersion : "411.86.202308081056-0" ,
1113+ },
1114+ },
1115+ },
1116+ },
1117+ expectUpgradeBlock : true ,
1118+ expectMessage : "Upgrades have been disabled because the cluster is using RHCOS boot image version 411.86.202308081056-0(RHEL version: 8.6), which is below the minimum required RHEL version " + ctrlcommon .RHCOSVersionBootImageSkewLimit + ". To enable upgrades, please update your boot images following the documentation at [TODO: insert link], or disable boot image skew enforcement at [TODO: insert link]" ,
1119+ expectError : false ,
1120+ },
1121+ {
1122+ name : "mode is manual with exact minimum RHCOS version" ,
1123+ featureGateEnabled : true ,
1124+ mcop : & opv1.MachineConfiguration {
1125+ ObjectMeta : metav1.ObjectMeta {Name : ctrlcommon .MCOOperatorKnobsObjectName },
1126+ Status : opv1.MachineConfigurationStatus {
1127+ BootImageSkewEnforcementStatus : opv1.BootImageSkewEnforcementStatus {
1128+ Mode : opv1 .BootImageSkewEnforcementModeStatusManual ,
1129+ Manual : opv1.ClusterBootImageManual {
1130+ Mode : opv1 .ClusterBootImageSpecModeRHCOSVersion ,
1131+ RHCOSVersion : "413.92.202402131523-0" ,
1132+ },
1133+ },
1134+ },
1135+ },
1136+ expectUpgradeBlock : false ,
1137+ expectMessage : "" ,
1138+ expectError : false ,
1139+ },
1140+ }
1141+
1142+ for _ , tc := range tests {
1143+ t .Run (tc .name , func (t * testing.T ) {
1144+ // Set up feature gate handler
1145+ enabledFeatures := []configv1.FeatureGateName {}
1146+ if tc .featureGateEnabled {
1147+ enabledFeatures = append (enabledFeatures , features .FeatureGateBootImageSkewEnforcement )
1148+ }
1149+ fgHandler := ctrlcommon .NewFeatureGatesHardcodedHandler (enabledFeatures , []configv1.FeatureGateName {})
1150+
1151+ // Set up mcopLister
1152+ mcopIndexer := cache .NewIndexer (cache .MetaNamespaceKeyFunc , cache.Indexers {cache .NamespaceIndex : cache .MetaNamespaceIndexFunc })
1153+ if tc .mcop != nil && ! tc .mcopNotFound {
1154+ mcopIndexer .Add (tc .mcop )
1155+ }
1156+ mcopLister := mcoplistersv1 .NewMachineConfigurationLister (mcopIndexer )
1157+
1158+ optr := & Operator {
1159+ fgHandler : fgHandler ,
1160+ mcopLister : mcopLister ,
1161+ }
1162+
1163+ upgradeBlock , message , err := optr .checkBootImageSkewUpgradeableGuard ()
1164+
1165+ if tc .expectError {
1166+ assert .Error (t , err )
1167+ } else {
1168+ assert .NoError (t , err )
1169+ }
1170+ assert .Equal (t , tc .expectUpgradeBlock , upgradeBlock , "upgrade block mismatch" )
1171+ assert .Equal (t , tc .expectMessage , message , "message mismatch" )
1172+ })
1173+ }
1174+ }
0 commit comments