@@ -2,7 +2,7 @@ package controller
2
2
3
3
import (
4
4
"testing"
5
- duration "time"
5
+ stdtime "time"
6
6
7
7
"github.com/atlassian/escalator/pkg/k8s"
8
8
"github.com/atlassian/escalator/pkg/k8s/resource"
@@ -39,7 +39,7 @@ func buildTestClient(nodes []*v1.Node, pods []*v1.Pod, nodeGroups []NodeGroupOpt
39
39
opts := Opts {
40
40
K8SClient : fakeClient ,
41
41
NodeGroups : nodeGroups ,
42
- ScanInterval : 1 * duration .Minute ,
42
+ ScanInterval : 1 * stdtime .Minute ,
43
43
DryMode : false ,
44
44
}
45
45
allPodLister , err := test .NewTestPodWatcher (pods , listerOptions .podListerOptions )
@@ -853,7 +853,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
853
853
args args
854
854
scaleUpWithCachedCapacity bool
855
855
runs int
856
- runInterval duration .Duration
856
+ runInterval stdtime .Duration
857
857
want int
858
858
err error
859
859
}{
@@ -879,7 +879,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
879
879
},
880
880
false ,
881
881
1 ,
882
- duration .Minute ,
882
+ stdtime .Minute ,
883
883
- 4 ,
884
884
nil ,
885
885
},
@@ -905,7 +905,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
905
905
},
906
906
false ,
907
907
5 ,
908
- duration .Minute ,
908
+ stdtime .Minute ,
909
909
- 2 ,
910
910
nil ,
911
911
},
@@ -931,7 +931,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
931
931
},
932
932
false ,
933
933
1 ,
934
- duration .Minute ,
934
+ stdtime .Minute ,
935
935
- 4 ,
936
936
nil ,
937
937
},
@@ -958,7 +958,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
958
958
},
959
959
false ,
960
960
1 ,
961
- duration .Minute ,
961
+ stdtime .Minute ,
962
962
1 ,
963
963
nil ,
964
964
},
@@ -985,7 +985,7 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
985
985
},
986
986
true ,
987
987
1 ,
988
- duration .Minute ,
988
+ stdtime .Minute ,
989
989
6 ,
990
990
nil ,
991
991
},
@@ -1060,3 +1060,250 @@ func TestScaleNodeGroup_MultipleRuns(t *testing.T) {
1060
1060
})
1061
1061
}
1062
1062
}
1063
+
1064
+ func TestScaleNodeGroupNodeMaxAge (t * testing.T ) {
1065
+ buildNode := func (creation stdtime.Time , tainted bool ) * v1.Node {
1066
+ return test .BuildTestNode (test.NodeOpts {
1067
+ CPU : int64 (1000 ),
1068
+ Mem : int64 (1000 ),
1069
+ Creation : creation ,
1070
+ Tainted : tainted ,
1071
+ })
1072
+ }
1073
+
1074
+ type args struct {
1075
+ nodes []* v1.Node
1076
+ pods []* v1.Pod
1077
+ nodeGroupOptions NodeGroupOptions
1078
+ listerOptions ListerOptions
1079
+ }
1080
+
1081
+ tests := []struct {
1082
+ name string
1083
+ args args
1084
+ expectedNodeDelta int
1085
+ err error
1086
+ }{
1087
+ {
1088
+ "max_node_age disabled" ,
1089
+ args {
1090
+ nodes : []* v1.Node {
1091
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1092
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), false ),
1093
+ buildNode (time .Now ().Add (- 36 * stdtime .Hour ), false ),
1094
+ },
1095
+ pods : nil ,
1096
+ nodeGroupOptions : NodeGroupOptions {
1097
+ Name : "default" ,
1098
+ CloudProviderGroupName : "default" ,
1099
+ MinNodes : 3 ,
1100
+ MaxNodes : 10 ,
1101
+ ScaleUpThresholdPercent : 70 ,
1102
+ MaxNodeAge : "0" ,
1103
+ },
1104
+ listerOptions : ListerOptions {},
1105
+ },
1106
+ 0 ,
1107
+ nil ,
1108
+ },
1109
+ {
1110
+ "max_node_age enabled, max node age 12 hours" ,
1111
+ args {
1112
+ nodes : []* v1.Node {
1113
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1114
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), false ),
1115
+ buildNode (time .Now ().Add (- 36 * stdtime .Hour ), false ),
1116
+ },
1117
+ pods : nil ,
1118
+ nodeGroupOptions : NodeGroupOptions {
1119
+ Name : "default" ,
1120
+ CloudProviderGroupName : "default" ,
1121
+ MinNodes : 3 ,
1122
+ MaxNodes : 10 ,
1123
+ ScaleUpThresholdPercent : 70 ,
1124
+ MaxNodeAge : "12h" ,
1125
+ },
1126
+ listerOptions : ListerOptions {},
1127
+ },
1128
+ 1 ,
1129
+ nil ,
1130
+ },
1131
+ {
1132
+ "max_node_age enabled, max node age 48 hours" ,
1133
+ args {
1134
+ nodes : []* v1.Node {
1135
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1136
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), false ),
1137
+ buildNode (time .Now ().Add (- 36 * stdtime .Hour ), false ),
1138
+ },
1139
+ pods : nil ,
1140
+ nodeGroupOptions : NodeGroupOptions {
1141
+ Name : "default" ,
1142
+ CloudProviderGroupName : "default" ,
1143
+ MinNodes : 3 ,
1144
+ MaxNodes : 10 ,
1145
+ ScaleUpThresholdPercent : 70 ,
1146
+ MaxNodeAge : "48h" ,
1147
+ },
1148
+ listerOptions : ListerOptions {},
1149
+ },
1150
+ 0 ,
1151
+ nil ,
1152
+ },
1153
+ {
1154
+ "max_node_age enabled, but not at node minimum" ,
1155
+ args {
1156
+ nodes : []* v1.Node {
1157
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1158
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), false ),
1159
+ buildNode (time .Now ().Add (- 36 * stdtime .Hour ), false ),
1160
+ },
1161
+ pods : nil ,
1162
+ nodeGroupOptions : NodeGroupOptions {
1163
+ Name : "default" ,
1164
+ CloudProviderGroupName : "default" ,
1165
+ MinNodes : 1 ,
1166
+ MaxNodes : 10 ,
1167
+ ScaleUpThresholdPercent : 70 ,
1168
+ MaxNodeAge : "12h" ,
1169
+ },
1170
+ listerOptions : ListerOptions {},
1171
+ },
1172
+ 0 ,
1173
+ nil ,
1174
+ },
1175
+ {
1176
+ "max_node_age enabled, but no nodes" ,
1177
+ args {
1178
+ nodes : nil ,
1179
+ pods : nil ,
1180
+ nodeGroupOptions : NodeGroupOptions {
1181
+ Name : "default" ,
1182
+ CloudProviderGroupName : "default" ,
1183
+ MinNodes : 1 ,
1184
+ MaxNodes : 10 ,
1185
+ ScaleUpThresholdPercent : 70 ,
1186
+ MaxNodeAge : "12h" ,
1187
+ },
1188
+ listerOptions : ListerOptions {},
1189
+ },
1190
+ 0 ,
1191
+ nil ,
1192
+ },
1193
+ {
1194
+ "max_node_age enabled, some nodes are tainted" ,
1195
+ args {
1196
+ nodes : []* v1.Node {
1197
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1198
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), false ),
1199
+ buildNode (time .Now ().Add (- 36 * stdtime .Hour ), true ),
1200
+ },
1201
+ pods : nil ,
1202
+ nodeGroupOptions : NodeGroupOptions {
1203
+ Name : "default" ,
1204
+ CloudProviderGroupName : "default" ,
1205
+ MinNodes : 1 ,
1206
+ MaxNodes : 10 ,
1207
+ ScaleUpThresholdPercent : 70 ,
1208
+ MaxNodeAge : "12h" ,
1209
+ },
1210
+ listerOptions : ListerOptions {},
1211
+ },
1212
+ 0 ,
1213
+ nil ,
1214
+ },
1215
+ {
1216
+ "max_node_age enabled, scaled down to zero" ,
1217
+ args {
1218
+ nodes : []* v1.Node {},
1219
+ pods : nil ,
1220
+ nodeGroupOptions : NodeGroupOptions {
1221
+ Name : "default" ,
1222
+ CloudProviderGroupName : "default" ,
1223
+ MinNodes : 0 ,
1224
+ MaxNodes : 10 ,
1225
+ ScaleUpThresholdPercent : 70 ,
1226
+ MaxNodeAge : "12h" ,
1227
+ },
1228
+ listerOptions : ListerOptions {},
1229
+ },
1230
+ 0 ,
1231
+ nil ,
1232
+ },
1233
+ {
1234
+ "max_node_age enabled, 1 tainted, 1 untainted" ,
1235
+ args {
1236
+ nodes : []* v1.Node {
1237
+ buildNode (time .Now ().Add (- 1 * stdtime .Hour ), false ),
1238
+ buildNode (time .Now ().Add (- 24 * stdtime .Hour ), true ),
1239
+ },
1240
+ pods : nil ,
1241
+ nodeGroupOptions : NodeGroupOptions {
1242
+ Name : "default" ,
1243
+ CloudProviderGroupName : "default" ,
1244
+ MinNodes : 1 ,
1245
+ MaxNodes : 10 ,
1246
+ ScaleUpThresholdPercent : 70 ,
1247
+ MaxNodeAge : "30m" ,
1248
+ },
1249
+ listerOptions : ListerOptions {},
1250
+ },
1251
+ 0 ,
1252
+ nil ,
1253
+ },
1254
+ }
1255
+
1256
+ for _ , tt := range tests {
1257
+ t .Run (tt .name , func (t * testing.T ) {
1258
+ nodeGroups := []NodeGroupOptions {tt .args .nodeGroupOptions }
1259
+ ngName := tt .args .nodeGroupOptions .Name
1260
+ client , opts , err := buildTestClient (tt .args .nodes , tt .args .pods , nodeGroups , tt .args .listerOptions )
1261
+ require .NoError (t , err )
1262
+
1263
+ // For these test cases we only use 1 node group/cloud provider node group
1264
+ nodeGroupSize := 1
1265
+
1266
+ // Create a test (mock) cloud provider
1267
+ testCloudProvider := test .NewCloudProvider (nodeGroupSize )
1268
+ testNodeGroup := test .NewNodeGroup (
1269
+ tt .args .nodeGroupOptions .CloudProviderGroupName ,
1270
+ tt .args .nodeGroupOptions .Name ,
1271
+ int64 (tt .args .nodeGroupOptions .MinNodes ),
1272
+ int64 (tt .args .nodeGroupOptions .MaxNodes ),
1273
+ int64 (len (tt .args .nodes )),
1274
+ )
1275
+ testCloudProvider .RegisterNodeGroup (testNodeGroup )
1276
+
1277
+ // Create a node group state with the mapping of node groups to the cloud providers node groups
1278
+ nodeGroupsState := BuildNodeGroupsState (nodeGroupsStateOpts {
1279
+ nodeGroups : nodeGroups ,
1280
+ client : * client ,
1281
+ })
1282
+
1283
+ controller := & Controller {
1284
+ Client : client ,
1285
+ Opts : opts ,
1286
+ stopChan : nil ,
1287
+ nodeGroups : nodeGroupsState ,
1288
+ cloudProvider : testCloudProvider ,
1289
+ }
1290
+
1291
+ nodesDelta , err := controller .scaleNodeGroup (ngName , nodeGroupsState [ngName ])
1292
+
1293
+ // Ensure there were no errors
1294
+ if tt .err == nil {
1295
+ require .NoError (t , err )
1296
+ } else {
1297
+ require .EqualError (t , tt .err , err .Error ())
1298
+ }
1299
+
1300
+ assert .Equal (t , tt .expectedNodeDelta , nodesDelta )
1301
+ if nodesDelta <= 0 {
1302
+ return
1303
+ }
1304
+
1305
+ // Ensure the node group on the cloud provider side scales up to the correct amount
1306
+ assert .Equal (t , int64 (len (tt .args .nodes )+ nodesDelta ), testNodeGroup .TargetSize ())
1307
+ })
1308
+ }
1309
+ }
0 commit comments