@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
1313limitations under the License.
1414*/
1515
16- // nolint: errcheck
16+ // nolint: errcheck, unparam
1717package mysqlcluster
1818
1919import (
@@ -81,6 +81,7 @@ var _ = Describe("MysqlCluster controller", func() {
8181 var (
8282 expectedRequest reconcile.Request
8383 cluster * mysqlcluster.MysqlCluster
84+ clusterKey types.NamespacedName
8485 secret * corev1.Secret
8586 components clusterComponents
8687 )
@@ -107,6 +108,10 @@ var _ = Describe("MysqlCluster controller", func() {
107108 SecretName : secret .Name ,
108109 },
109110 })
111+ clusterKey = types.NamespacedName {
112+ Name : cluster .Name ,
113+ Namespace : cluster .Namespace ,
114+ }
110115
111116 components = []runtime.Object {
112117 & appsv1.StatefulSet {
@@ -147,6 +152,7 @@ var _ = Describe("MysqlCluster controller", func() {
147152 },
148153 }
149154
155+ By ("create the MySQL cluster" )
150156 Expect (c .Create (context .TODO (), secret )).To (Succeed ())
151157 Expect (c .Create (context .TODO (), cluster .Unwrap ())).To (Succeed ())
152158
@@ -169,6 +175,7 @@ var _ = Describe("MysqlCluster controller", func() {
169175
170176 // We need to make sure that the controller does not create infinite
171177 // loops
178+ By ("wait for no more reconcile requests" )
172179 Consistently (requests ).ShouldNot (Receive (Equal (expectedRequest )))
173180 })
174181
@@ -247,6 +254,92 @@ var _ = Describe("MysqlCluster controller", func() {
247254 Eventually (requests , timeout ).Should (Receive (Equal (expectedRequest )))
248255 Eventually (getClusterConditions (c , cluster ), timeout ).Should (haveCondWithStatus (api .ClusterConditionReady , corev1 .ConditionTrue ))
249256 })
257+ It ("should label pods as healthy and as master accordingly" , func () {
258+ pod0 := getPod (cluster , 0 )
259+ Expect (c .Create (context .TODO (), pod0 )).To (Succeed ())
260+ pod1 := getPod (cluster , 1 )
261+ Expect (c .Create (context .TODO (), pod1 )).To (Succeed ())
262+ pod2 := getPod (cluster , 2 )
263+ Expect (c .Create (context .TODO (), pod2 )).To (Succeed ())
264+
265+ // update cluster conditions
266+ By ("update cluster status" )
267+ Expect (c .Get (context .TODO (), clusterKey , cluster .Unwrap ())).To (Succeed ())
268+ cluster .Status .Nodes = []api.NodeStatus {
269+ nodeStatusForPod (cluster , pod0 , true , false , false ),
270+ nodeStatusForPod (cluster , pod1 , false , false , true ),
271+ nodeStatusForPod (cluster , pod2 , false , false , false ),
272+ }
273+ Expect (c .Status ().Update (context .TODO (), cluster .Unwrap ())).To (Succeed ())
274+
275+ Eventually (requests , timeout ).Should (Receive (Equal (expectedRequest )))
276+
277+ // assert pods labels
278+ // master
279+ Expect (c .Get (context .TODO (), objToKey (pod0 ), pod0 )).To (Succeed ())
280+ Expect (pod0 ).To (haveLabelWithValue ("role" , "master" ))
281+ Expect (pod0 ).To (haveLabelWithValue ("healthy" , "yes" ))
282+
283+ // replica
284+ Expect (c .Get (context .TODO (), objToKey (pod1 ), pod1 )).To (Succeed ())
285+ Expect (pod1 ).To (haveLabelWithValue ("role" , "replica" ))
286+ Expect (pod1 ).To (haveLabelWithValue ("healthy" , "yes" ))
287+ })
288+ It ("should label pods as master eaven if pods does not exists" , func () {
289+ pod0 := getPod (cluster , 0 )
290+ Expect (c .Create (context .TODO (), pod0 )).To (Succeed ())
291+ pod1 := getPod (cluster , 1 )
292+ pod2 := getPod (cluster , 2 )
293+
294+ // update cluster conditions
295+ By ("update cluster status" )
296+ Expect (c .Get (context .TODO (), clusterKey , cluster .Unwrap ())).To (Succeed ())
297+ cluster .Status .Nodes = []api.NodeStatus {
298+ nodeStatusForPod (cluster , pod0 , true , false , false ),
299+ nodeStatusForPod (cluster , pod1 , false , false , false ),
300+ nodeStatusForPod (cluster , pod2 , false , false , false ),
301+ }
302+ Expect (c .Status ().Update (context .TODO (), cluster .Unwrap ())).To (Succeed ())
303+
304+ Eventually (requests , timeout ).Should (Receive (Equal (expectedRequest )))
305+
306+ // assert pods labels
307+ // master
308+ Expect (c .Get (context .TODO (), objToKey (pod0 ), pod0 )).To (Succeed ())
309+ Expect (pod0 ).To (haveLabelWithValue ("role" , "master" ))
310+ Expect (pod0 ).To (haveLabelWithValue ("healthy" , "yes" ))
311+
312+ // check pod is not created
313+ Expect (c .Get (context .TODO (), objToKey (pod1 ), pod1 )).ToNot (Succeed ())
314+ })
315+ It ("should label as unhealthy if lagged" , func () {
316+ pod0 := getPod (cluster , 0 )
317+ Expect (c .Create (context .TODO (), pod0 )).To (Succeed ())
318+ pod1 := getPod (cluster , 1 )
319+ Expect (c .Create (context .TODO (), pod1 )).To (Succeed ())
320+
321+ // update cluster conditions
322+ By ("update cluster status" )
323+ Expect (c .Get (context .TODO (), clusterKey , cluster .Unwrap ())).To (Succeed ())
324+ cluster .Status .Nodes = []api.NodeStatus {
325+ nodeStatusForPod (cluster , pod0 , false , true , false ),
326+ nodeStatusForPod (cluster , pod1 , true , false , true ),
327+ }
328+ Expect (c .Status ().Update (context .TODO (), cluster .Unwrap ())).To (Succeed ())
329+
330+ Eventually (requests , timeout ).Should (Receive (Equal (expectedRequest )))
331+
332+ // assert pods labels
333+ // master
334+ Expect (c .Get (context .TODO (), objToKey (pod0 ), pod0 )).To (Succeed ())
335+ Expect (pod0 ).To (haveLabelWithValue ("role" , "replica" ))
336+ Expect (pod0 ).To (haveLabelWithValue ("healthy" , "no" ))
337+
338+ // replica
339+ Expect (c .Get (context .TODO (), objToKey (pod1 ), pod1 )).To (Succeed ())
340+ Expect (pod1 ).To (haveLabelWithValue ("role" , "master" ))
341+ Expect (pod1 ).To (haveLabelWithValue ("healthy" , "yes" ))
342+ })
250343 })
251344 })
252345})
@@ -257,6 +350,65 @@ func removeAllCreatedResource(c client.Client, clusterComps []runtime.Object) {
257350 }
258351}
259352
353+ func objToKey (o runtime.Object ) types.NamespacedName {
354+ obj , _ := o .(* corev1.Pod )
355+ return types.NamespacedName {
356+ Name : obj .Name ,
357+ Namespace : obj .Namespace ,
358+ }
359+ }
360+
361+ func getPod (cluster * mysqlcluster.MysqlCluster , index int ) * corev1.Pod {
362+ return & corev1.Pod {
363+ ObjectMeta : metav1.ObjectMeta {
364+ Name : fmt .Sprintf ("%s-%d" , cluster .GetNameForResource (mysqlcluster .StatefulSet ), index ),
365+ Namespace : cluster .Namespace ,
366+ },
367+ Spec : corev1.PodSpec {
368+ Containers : []corev1.Container {
369+ corev1.Container {
370+ Name : "dummy" ,
371+ Image : "dummy" ,
372+ },
373+ },
374+ },
375+ }
376+ }
377+
378+ func nodeStatusForPod (cluster * mysqlcluster.MysqlCluster , pod * corev1.Pod , master , lagged , replicating bool ) api.NodeStatus {
379+ name := fmt .Sprintf ("%s.%s.%s" , pod .Name , cluster .GetNameForResource (mysqlcluster .HeadlessSVC ), pod .Namespace )
380+
381+ boolToStatus := func (c bool ) corev1.ConditionStatus {
382+ if c {
383+ return corev1 .ConditionTrue
384+ }
385+ return corev1 .ConditionFalse
386+ }
387+
388+ t := time .Now ()
389+
390+ return api.NodeStatus {
391+ Name : name ,
392+ Conditions : []api.NodeCondition {
393+ api.NodeCondition {
394+ Type : api .NodeConditionMaster ,
395+ Status : boolToStatus (master ),
396+ LastTransitionTime : metav1 .NewTime (t ),
397+ },
398+ api.NodeCondition {
399+ Type : api .NodeConditionLagged ,
400+ Status : boolToStatus (lagged ),
401+ LastTransitionTime : metav1 .NewTime (t ),
402+ },
403+ api.NodeCondition {
404+ Type : api .NodeConditionReplicating ,
405+ Status : boolToStatus (replicating ),
406+ LastTransitionTime : metav1 .NewTime (t ),
407+ },
408+ },
409+ }
410+ }
411+
260412// getClusterConditions is a helper func that returns a functions that returns cluster status conditions
261413func getClusterConditions (c client.Client , cluster * mysqlcluster.MysqlCluster ) func () []api.ClusterCondition {
262414 return func () []api.ClusterCondition {
@@ -273,3 +425,11 @@ func haveCondWithStatus(condType api.ClusterConditionType, status corev1.Conditi
273425 "Status" : Equal (status ),
274426 }))
275427}
428+
429+ func haveLabelWithValue (label , value string ) gomegatypes.GomegaMatcher {
430+ return PointTo (MatchFields (IgnoreExtras , Fields {
431+ "ObjectMeta" : MatchFields (IgnoreExtras , Fields {
432+ "Labels" : HaveKeyWithValue (label , value ),
433+ }),
434+ }))
435+ }
0 commit comments