1+ //@flow
12import { createSelector } from 'reselect' ;
23import {
34 NODE_ALERTS_GROUP ,
@@ -13,43 +14,77 @@ import {
1314} from '../constants' ;
1415import { compareHealth } from './utils' ;
1516import type { IPInterfaces } from './salt/api' ;
17+ import type { RootState } from '../ducks/reducer' ;
18+ import type { NodesState } from '../ducks/app/nodes' ;
19+ import type { AlertsState } from '../ducks/app/alerts' ;
20+ import type { Brand } from '../services/api' ;
1621
1722const METALK8S_CONTROL_PLANE_IP = 'metalk8s:control_plane_ip' ;
1823const METALK8S_WORKLOAD_PLANE_IP = 'metalk8s:workload_plane_ip' ;
1924const IP_INTERFACES = 'ip_interfaces' ;
2025
26+ // Note that: Reverse the selectors and result in order to type unknown number of selectors.
27+ export const createTypedSelector : < T > (
28+ selectorsResult: (...result: any) => T ,
29+ ...selectors : ( ( state : RootState ) => any ) [ ]
30+ ) => T = ( selectorsResult , ...selectors ) =>
31+ createSelector ( ...selectors , selectorsResult ) ;
32+
33+ type NodetableList = {
34+ name : { name : string , controlPlaneIP : string , workloadPlaneIP : string } ,
35+ status : {
36+ status : 'ready' | 'not_ready' | 'unknown' ,
37+ conditions : (
38+ | 'DiskPressure'
39+ | 'MemoryPressure'
40+ | 'PIDPressure'
41+ | 'NetworkUnavailable'
42+ | 'Unschedulable'
43+ ) [ ] ,
44+ statusTextColor : string ,
45+ computedStatus : [ ] ,
46+ } ,
47+ health : {
48+ health : 'health' | 'warning' | 'critical' | 'none' ,
49+ totalAlertsCounter : number ,
50+ criticalAlertsCounter : number ,
51+ warningAlertsCounter : number ,
52+ } ,
53+ roles : string ,
54+ } [ ] ;
55+
2156const IPsInfoSelector = ( state ) => state . app . nodes . IPsInfo ;
2257const nodesSelector = ( state ) => state . app . nodes . list ;
2358const brandSelector = ( state ) => state . config . theme . brand ;
2459const alertsSelector = ( state ) => state . app . alerts . list ;
2560
2661// Return the data used by the Node list table
27- export const getNodeListData = createSelector (
28- nodesSelector ,
29- IPsInfoSelector ,
30- brandSelector ,
31- alertsSelector ,
32- ( nodes , nodeIPsInfo , brand , alerts ) => {
62+ export const getNodeListData = createTypedSelector < NodetableList > (
63+ (
64+ nodes : $PropertyType < NodesState , 'list' > ,
65+ nodeIPsInfo : NodesState ,
66+ brand : Brand ,
67+ alerts : $PropertyType < AlertsState , 'list' > ,
68+ ) => {
3369 const mapped =
34- nodes ?. map ( ( node ) => {
35- const IPsInfo = nodeIPsInfo ?. [ node . name ] ;
70+ nodes . map ( ( node ) => {
71+ const conditions = node . conditions ;
72+ const IPsInfo = nodeIPsInfo [ node . name ] ;
3673 let statusTextColor , health ;
37- const alertsNode = alerts ? .filter (
74+ const alertsNode = alerts . filter (
3875 ( alert ) =>
39- NODE_ALERTS_GROUP . includes ( alert ? .labels ? .alertname ) &&
76+ NODE_ALERTS_GROUP . includes ( alert . labels . alertname ) &&
4077 `${ node . internalIP } :${ PORT_NODE_EXPORTER } ` ===
4178 alert . labels . instance ,
4279 ) ;
4380
44- const totalAlertsCounter = alertsNode ?. length ?? - 1 ;
45- const criticalAlertsCounter =
46- alertsNode ?. filter (
47- ( alert ) => alert . labels . severity === STATUS_CRITICAL ,
48- ) ?. length ?? - 1 ;
49- const warningAlertsCounter =
50- alertsNode ?. filter (
51- ( alert ) => alert . labels . severity === STATUS_WARNING ,
52- ) ?. length ?? - 1 ;
81+ const totalAlertsCounter = alertsNode . length ;
82+ const criticalAlertsCounter = alertsNode . filter (
83+ ( alert ) => alert . labels . severity === STATUS_CRITICAL ,
84+ ) . length ;
85+ const warningAlertsCounter = alertsNode . filter (
86+ ( alert ) => alert . labels . severity === STATUS_WARNING ,
87+ ) . length ;
5388
5489 if ( criticalAlertsCounter > 0 ) {
5590 health = STATUS_CRITICAL ;
@@ -64,86 +99,88 @@ export const getNodeListData = createSelector(
6499 }
65100
66101 const computedStatus = [ ] ;
67- // The rules of the color of the node status
68- // "green" when status.conditions['Ready'] == True and all other conditions are false
69- // "yellow" when status.conditions['Ready'] == True and some other conditions are true
70- // "red" when status.conditions['Ready'] == False
71- // "grey" when there is no status.conditions
72- if (
73- node ?. status === API_STATUS_READY &&
74- node ?. conditions . length === 0
75- ) {
76- statusTextColor = brand ?. healthy ;
102+ /* The rules of the color of the node status
103+ <green> when status.conditions['Ready'] == True and all other conditions are false
104+ <yellow> when status.conditions['Ready'] == True and some other conditions are true
105+ <red> when status.conditions['Ready'] == False
106+ <grey> when there is no status.conditions */
107+ if ( node . status === API_STATUS_READY && conditions . length === 0 ) {
108+ statusTextColor = brand . healthy ;
77109 computedStatus . push ( API_STATUS_READY ) ;
78110 } else if (
79- node ? .status === API_STATUS_READY &&
80- node ?. conditions . length !== 0
111+ node . status === API_STATUS_READY &&
112+ conditions . length !== 0
81113 ) {
82- statusTextColor = brand ? .warning ;
83- nodes . conditions . map ( ( cond ) => {
114+ statusTextColor = brand . warning ;
115+ conditions . map ( ( cond ) => {
84116 return computedStatus . push ( cond ) ;
85117 } ) ;
86118 } else if ( node . deploying && node . status === API_STATUS_UNKNOWN ) {
87- statusTextColor = brand ? .textSecondary ;
119+ statusTextColor = brand . textSecondary ;
88120 computedStatus . push ( API_STATUS_DEPLOYING ) ;
89121 health = STATUS_NONE ;
90- } else if ( node ? .status !== API_STATUS_READY ) {
91- statusTextColor = brand ? .critical ;
122+ } else if ( node . status !== API_STATUS_READY ) {
123+ statusTextColor = brand . critical ;
92124 computedStatus . push ( API_STATUS_NOT_READY ) ;
93125 health = STATUS_NONE ;
94126 } else {
95- statusTextColor = brand ? .textSecondary ;
127+ statusTextColor = brand . textSecondary ;
96128 computedStatus . push ( API_STATUS_UNKNOWN ) ;
97129 health = STATUS_NONE ;
98130 }
99131
100132 return {
101133 // According to the design, the IPs of Control Plane and Workload Plane are in the same Cell with Name
102134 name : {
103- name : node ? .name ,
135+ name : node . name ,
104136 controlPlaneIP : IPsInfo ?. controlPlane ?. ip ,
105137 workloadPlaneIP : IPsInfo ?. workloadPlane ?. ip ,
106138 } ,
107139 status : {
108- status : node ? .status ,
109- conditions : node ? .conditions ,
140+ status : node . status ,
141+ conditions : node . conditions ,
110142 statusTextColor,
111143 computedStatus,
112144 } ,
113- roles : node ? .roles ,
145+ roles : node . roles ,
114146 health : {
115147 health,
116148 totalAlertsCounter,
117149 criticalAlertsCounter,
118150 warningAlertsCounter,
119151 } ,
120152 } ;
121- } ) ?? [ ] ;
153+ } ) || [ ] ;
122154
123155 return mapped . sort ( ( a , b ) =>
124156 compareHealth ( b . health . health , a . health . health ) ,
125157 ) ;
126158 } ,
159+ nodesSelector ,
160+ IPsInfoSelector ,
161+ brandSelector ,
162+ alertsSelector ,
127163) ;
128164
129- // This function returns the IP and interface of Control Plane and Workload Plane for each Node
130- // Arguments:
131- // ipsInterfacesObject =
132- // {
133- // ip_interface: {
134- // eth1:['10.0.1.42', 'fe80::f816:3eff:fe25:5843'],
135- // eth3:['10.100.0.2', 'fe80::f816:3eff:fe37:2f34']
136- // },
137- // metalk8s:control_plane_ip: "10.0.1.42",
138- // metalk8s:workload_plane_ip: "10.100.0.2"
139- // }
140- // Return
141- // {
142- // controlPlane: { ip: '10.0.1.42', interface: 'eth1'}
143- // workloadPlane: { ip: '10.100.0.2', interface: 'eth3'},
144- // }
165+ /*
166+ This function returns the IP and interface of Control Plane and Workload Plane for each Node
167+ Arguments:
168+ ipsInterfacesObject = {
169+ ip_interface: {
170+ eth1:['10.0.1.42', 'fe80::f816:3eff:fe25:5843'],
171+ eth3:['10.100.0.2', 'fe80::f816:3eff:fe37:2f34']
172+ },
173+ metalk8s:control_plane_ip: "10.0.1.42",
174+ metalk8s:workload_plane_ip: "10.100.0.2"
175+ }
176+ Return
177+ {
178+ controlPlane: { ip: '10.0.1.42', interface: 'eth1'}
179+ workloadPlane: { ip: '10.100.0.2', interface: 'eth3'},
180+ }
181+ */
145182export const nodesCPWPIPsInterface = (
146- IPsInterfacesObject : IPInterfaces | boolean ,
183+ IPsInterfacesObject : IPInterfaces | false ,
147184) : {
148185 controlPlane : { ip : string , interface : string } ,
149186 workloadPlane : { ip : string , interface : string } ,
@@ -158,19 +195,21 @@ export const nodesCPWPIPsInterface = (
158195 return {
159196 controlPlane : {
160197 ip : IPsInterfacesObject [ METALK8S_CONTROL_PLANE_IP ] ,
161- interface : Object . keys ( IPsInterfacesObject [ IP_INTERFACES ] ) . find ( ( en ) =>
162- IPsInterfacesObject [ IP_INTERFACES ] [ en ] . includes (
163- IPsInterfacesObject [ METALK8S_CONTROL_PLANE_IP ] ,
164- ) ,
165- ) ,
198+ interface :
199+ Object . keys ( IPsInterfacesObject [ IP_INTERFACES ] ) . find ( ( en ) =>
200+ IPsInterfacesObject [ IP_INTERFACES ] [ en ] . includes (
201+ IPsInterfacesObject [ METALK8S_CONTROL_PLANE_IP ] ,
202+ ) ,
203+ ) || '' ,
166204 } ,
167205 workloadPlane : {
168206 ip : IPsInterfacesObject [ METALK8S_WORKLOAD_PLANE_IP ] ,
169- interface : Object . keys ( IPsInterfacesObject [ IP_INTERFACES ] ) . find ( ( en ) =>
170- IPsInterfacesObject [ IP_INTERFACES ] [ en ] . includes (
171- IPsInterfacesObject [ METALK8S_WORKLOAD_PLANE_IP ] ,
172- ) ,
173- ) ,
207+ interface :
208+ Object . keys ( IPsInterfacesObject [ IP_INTERFACES ] ) . find ( ( en ) =>
209+ IPsInterfacesObject [ IP_INTERFACES ] [ en ] . includes (
210+ IPsInterfacesObject [ METALK8S_WORKLOAD_PLANE_IP ] ,
211+ ) ,
212+ ) || '' ,
174213 } ,
175214 } ;
176215} ;
0 commit comments