]>
Commit | Line | Data |
---|---|---|
95d0de89 DC |
1 | Ext.define('PVE.ceph.Services', { |
2 | extend: 'Ext.panel.Panel', | |
3 | alias: 'widget.pveCephServices', | |
4 | ||
5 | layout: { | |
6 | type: 'hbox', | |
f6710aac | 7 | align: 'stretch', |
95d0de89 DC |
8 | }, |
9 | ||
10 | bodyPadding: '0 5 20', | |
11 | defaults: { | |
12 | xtype: 'box', | |
13 | style: { | |
8058410f | 14 | 'text-align': 'center', |
f6710aac | 15 | }, |
95d0de89 DC |
16 | }, |
17 | ||
18 | items: [ | |
19 | { | |
20 | flex: 1, | |
21 | xtype: 'pveCephServiceList', | |
22 | itemId: 'mons', | |
f6710aac | 23 | title: gettext('Monitors'), |
95d0de89 DC |
24 | }, |
25 | { | |
26 | flex: 1, | |
27 | xtype: 'pveCephServiceList', | |
28 | itemId: 'mgrs', | |
f6710aac | 29 | title: gettext('Managers'), |
95d0de89 DC |
30 | }, |
31 | { | |
32 | flex: 1, | |
33 | xtype: 'pveCephServiceList', | |
34 | itemId: 'mdss', | |
f6710aac TL |
35 | title: gettext('Meta Data Servers'), |
36 | }, | |
95d0de89 DC |
37 | ], |
38 | ||
39 | updateAll: function(metadata, status) { | |
40 | var me = this; | |
41 | ||
42 | var healthstates = { | |
43 | 'HEALTH_UNKNOWN': 0, | |
44 | 'HEALTH_ERR': 1, | |
45 | 'HEALTH_WARN': 2, | |
23c83a3a DC |
46 | 'HEALTH_UPGRADE': 3, |
47 | 'HEALTH_OLD': 4, | |
f6710aac | 48 | 'HEALTH_OK': 5, |
95d0de89 DC |
49 | }; |
50 | var healthmap = [ | |
51 | 'HEALTH_UNKNOWN', | |
52 | 'HEALTH_ERR', | |
53 | 'HEALTH_WARN', | |
23c83a3a | 54 | 'HEALTH_UPGRADE', |
95d0de89 | 55 | 'HEALTH_OLD', |
f6710aac | 56 | 'HEALTH_OK', |
95d0de89 DC |
57 | ]; |
58 | var reduceFn = function(first, second) { | |
59 | return first + '\n' + second.message; | |
60 | }; | |
95d0de89 DC |
61 | var maxversion = "00.0.00"; |
62 | Object.values(metadata.version || {}).forEach(function(version) { | |
4f71a0ff | 63 | if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) { |
95d0de89 DC |
64 | maxversion = version; |
65 | } | |
66 | }); | |
67 | var i; | |
68 | var quorummap = (status && status.quorum_names) ? status.quorum_names : []; | |
69 | var monmessages = {}; | |
70 | var mgrmessages = {}; | |
71 | var mdsmessages = {}; | |
72 | if (status) { | |
73 | if (status.health) { | |
74 | Ext.Object.each(status.health.checks, function(key, value, obj) { | |
75 | if (!Ext.String.startsWith(key, "MON_")) { | |
76 | return; | |
77 | } | |
78 | ||
9e546001 DC |
79 | var i; |
80 | for (i = 0; i < value.detail.length; i++) { | |
81 | var match = value.detail[i].message.match(/mon.([a-zA-Z0-9\-\.]+)/); | |
82 | if (!match) { | |
83 | continue; | |
84 | } | |
85 | var monid = match[1]; | |
95d0de89 | 86 | |
9e546001 DC |
87 | if (!monmessages[monid]) { |
88 | monmessages[monid] = { | |
89 | worstSeverity: healthstates.HEALTH_OK, | |
f6710aac | 90 | messages: [], |
9e546001 DC |
91 | }; |
92 | } | |
95d0de89 DC |
93 | |
94 | ||
9e546001 DC |
95 | monmessages[monid].messages.push( |
96 | PVE.Utils.get_ceph_icon_html(value.severity, true) + | |
f6710aac | 97 | Ext.Array.reduce(value.detail, reduceFn, ''), |
9e546001 DC |
98 | ); |
99 | if (healthstates[value.severity] < monmessages[monid].worstSeverity) { | |
100 | monmessages[monid].worstSeverity = healthstates[value.severity]; | |
101 | } | |
95d0de89 DC |
102 | } |
103 | }); | |
104 | } | |
105 | ||
106 | if (status.mgrmap) { | |
107 | mgrmessages[status.mgrmap.active_name] = "active"; | |
108 | status.mgrmap.standbys.forEach(function(mgr) { | |
109 | mgrmessages[mgr.name] = "standby"; | |
110 | }); | |
111 | } | |
112 | ||
113 | if (status.fsmap) { | |
114 | status.fsmap.by_rank.forEach(function(mds) { | |
115 | mdsmessages[mds.name] = 'rank: ' + mds.rank + "; " + mds.status; | |
116 | }); | |
117 | } | |
118 | } | |
119 | ||
120 | var checks = { | |
121 | mon: function(mon) { | |
122 | if (quorummap.indexOf(mon.name) !== -1) { | |
123 | mon.health = healthstates.HEALTH_OK; | |
124 | } else { | |
125 | mon.health = healthstates.HEALTH_ERR; | |
126 | } | |
127 | if (monmessages[mon.name]) { | |
128 | if (monmessages[mon.name].worstSeverity < mon.health) { | |
129 | mon.health = monmessages[mon.name].worstSeverity; | |
130 | } | |
131 | Array.prototype.push.apply(mon.messages, monmessages[mon.name].messages); | |
132 | } | |
133 | return mon; | |
134 | }, | |
135 | mgr: function(mgr) { | |
136 | if (mgrmessages[mgr.name] === 'active') { | |
137 | mgr.title = '<b>' + mgr.title + '</b>'; | |
138 | mgr.statuses.push(gettext('Status') + ': <b>active</b>'); | |
139 | } else if (mgrmessages[mgr.name] === 'standby') { | |
140 | mgr.statuses.push(gettext('Status') + ': standby'); | |
141 | } else if (mgr.health > healthstates.HEALTH_WARN) { | |
142 | mgr.health = healthstates.HEALTH_WARN; | |
143 | } | |
144 | ||
145 | return mgr; | |
146 | }, | |
147 | mds: function(mds) { | |
148 | if (mdsmessages[mds.name]) { | |
149 | mds.title = '<b>' + mds.title + '</b>'; | |
150 | mds.statuses.push(gettext('Status') + ': <b>' + mdsmessages[mds.name]+"</b>"); | |
151 | } else if (mds.addr !== Proxmox.Utils.unknownText) { | |
152 | mds.statuses.push(gettext('Status') + ': standby'); | |
153 | } | |
154 | ||
155 | return mds; | |
f6710aac | 156 | }, |
95d0de89 DC |
157 | }; |
158 | ||
df598da5 | 159 | for (let type of ['mon', 'mgr', 'mds']) { |
95d0de89 DC |
160 | var ids = Object.keys(metadata[type] || {}); |
161 | me[type] = {}; | |
162 | ||
df598da5 | 163 | for (let id of ids) { |
95d0de89 DC |
164 | var tmp = id.split('@'); |
165 | var name = tmp[0]; | |
166 | var host = tmp[1]; | |
167 | var result = { | |
168 | id: id, | |
169 | health: healthstates.HEALTH_OK, | |
170 | statuses: [], | |
171 | messages: [], | |
172 | name: name, | |
173 | title: metadata[type][id].name || name, | |
174 | host: host, | |
175 | version: PVE.Utils.parse_ceph_version(metadata[type][id]), | |
176 | service: metadata[type][id].service, | |
f6710aac | 177 | addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText, |
95d0de89 DC |
178 | }; |
179 | ||
180 | result.statuses = [ | |
181 | gettext('Host') + ": " + result.host, | |
f6710aac | 182 | gettext('Address') + ": " + result.addr, |
95d0de89 DC |
183 | ]; |
184 | ||
185 | if (checks[type]) { | |
186 | result = checks[type](result); | |
187 | } | |
188 | ||
189 | if (result.service && !result.version) { | |
190 | result.messages.push( | |
191 | PVE.Utils.get_ceph_icon_html('HEALTH_UNKNOWN', true) + | |
f6710aac | 192 | gettext('Stopped'), |
95d0de89 DC |
193 | ); |
194 | result.health = healthstates.HEALTH_UNKNOWN; | |
195 | } | |
196 | ||
197 | if (!result.version && result.addr === Proxmox.Utils.unknownText) { | |
198 | result.health = healthstates.HEALTH_UNKNOWN; | |
199 | } | |
200 | ||
201 | if (result.version) { | |
202 | result.statuses.push(gettext('Version') + ": " + result.version); | |
203 | ||
204 | if (result.version != maxversion) { | |
0575611e DC |
205 | if (metadata.version[result.host] === maxversion) { |
206 | if (result.health > healthstates.HEALTH_OLD) { | |
207 | result.health = healthstates.HEALTH_OLD; | |
208 | } | |
209 | result.messages.push( | |
210 | PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) + | |
f6710aac | 211 | gettext('A newer version was installed but old version still running, please restart'), |
0575611e DC |
212 | ); |
213 | } else { | |
214 | if (result.health > healthstates.HEALTH_UPGRADE) { | |
215 | result.health = healthstates.HEALTH_UPGRADE; | |
216 | } | |
217 | result.messages.push( | |
218 | PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE', true) + | |
f6710aac | 219 | gettext('Other cluster members use a newer version of this service, please upgrade and restart'), |
0575611e | 220 | ); |
95d0de89 | 221 | } |
95d0de89 DC |
222 | } |
223 | } | |
224 | ||
225 | result.statuses.push(''); // empty line | |
226 | result.text = result.statuses.concat(result.messages).join('<br>'); | |
227 | ||
228 | result.health = healthmap[result.health]; | |
229 | ||
230 | me[type][id] = result; | |
231 | } | |
232 | } | |
233 | ||
234 | me.getComponent('mons').updateAll(Object.values(me.mon)); | |
235 | me.getComponent('mgrs').updateAll(Object.values(me.mgr)); | |
236 | me.getComponent('mdss').updateAll(Object.values(me.mds)); | |
f6710aac | 237 | }, |
95d0de89 DC |
238 | }); |
239 | ||
240 | Ext.define('PVE.ceph.ServiceList', { | |
241 | extend: 'Ext.container.Container', | |
242 | xtype: 'pveCephServiceList', | |
243 | ||
244 | style: { | |
8058410f | 245 | 'text-align': 'center', |
95d0de89 DC |
246 | }, |
247 | defaults: { | |
248 | xtype: 'box', | |
249 | style: { | |
8058410f | 250 | 'text-align': 'center', |
f6710aac | 251 | }, |
95d0de89 DC |
252 | }, |
253 | ||
254 | items: [ | |
255 | { | |
256 | itemId: 'title', | |
257 | data: { | |
f6710aac | 258 | title: '', |
95d0de89 | 259 | }, |
f6710aac TL |
260 | tpl: '<h3>{title}</h3>', |
261 | }, | |
95d0de89 DC |
262 | ], |
263 | ||
264 | updateAll: function(list) { | |
265 | var me = this; | |
266 | me.suspendLayout = true; | |
267 | ||
268 | var i; | |
df598da5 | 269 | list.sort((a, b) => a.id > b.id ? 1 : a.id < b.id ? -1 : 0); |
95d0de89 DC |
270 | var ids = {}; |
271 | if (me.ids) { | |
df598da5 | 272 | me.ids.forEach(id => ids[id] = true); |
95d0de89 DC |
273 | } |
274 | for (i = 0; i < list.length; i++) { | |
275 | var service = me.getComponent(list[i].id); | |
276 | if (!service) { | |
277 | // since services are already sorted, and | |
278 | // we always have a sorted list | |
279 | // we can add it at the service+1 position (because of the title) | |
280 | service = me.insert(i+1, { | |
281 | xtype: 'pveCephServiceWidget', | |
f6710aac | 282 | itemId: list[i].id, |
95d0de89 DC |
283 | }); |
284 | if (!me.ids) { | |
285 | me.ids = []; | |
286 | } | |
287 | me.ids.push(list[i].id); | |
288 | } else { | |
289 | delete ids[list[i].id]; | |
290 | } | |
291 | service.updateService(list[i].title, list[i].text, list[i].health); | |
292 | } | |
293 | ||
294 | Object.keys(ids).forEach(function(id) { | |
295 | me.remove(id); | |
296 | }); | |
297 | me.suspendLayout = false; | |
298 | me.updateLayout(); | |
299 | }, | |
300 | ||
301 | initComponent: function() { | |
302 | var me = this; | |
303 | me.callParent(); | |
304 | me.getComponent('title').update({ | |
f6710aac | 305 | title: me.title, |
95d0de89 | 306 | }); |
f6710aac | 307 | }, |
95d0de89 DC |
308 | }); |
309 | ||
95d0de89 DC |
310 | Ext.define('PVE.ceph.ServiceWidget', { |
311 | extend: 'Ext.Component', | |
312 | alias: 'widget.pveCephServiceWidget', | |
313 | ||
314 | userCls: 'monitor inline-block', | |
315 | data: { | |
316 | title: '0', | |
317 | health: 'HEALTH_ERR', | |
318 | text: '', | |
f6710aac | 319 | iconCls: PVE.Utils.get_health_icon(), |
95d0de89 DC |
320 | }, |
321 | ||
322 | tpl: [ | |
323 | '{title}: ', | |
f6710aac | 324 | '<i class="fa fa-fw {iconCls}"></i>', |
95d0de89 DC |
325 | ], |
326 | ||
327 | updateService: function(title, text, health) { | |
328 | var me = this; | |
329 | ||
330 | me.update(Ext.apply(me.data, { | |
331 | health: health, | |
332 | text: text, | |
333 | title: title, | |
f6710aac | 334 | iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[health]), |
95d0de89 DC |
335 | })); |
336 | ||
337 | if (me.tooltip) { | |
338 | me.tooltip.setHtml(text); | |
339 | } | |
340 | }, | |
341 | ||
342 | listeners: { | |
343 | destroy: function() { | |
344 | var me = this; | |
345 | if (me.tooltip) { | |
346 | me.tooltip.destroy(); | |
347 | delete me.tooltip; | |
348 | } | |
349 | }, | |
350 | mouseenter: { | |
351 | element: 'el', | |
352 | fn: function(events, element) { | |
353 | var me = this.component; | |
354 | if (!me) { | |
355 | return; | |
356 | } | |
357 | if (!me.tooltip) { | |
358 | me.tooltip = Ext.create('Ext.tip.ToolTip', { | |
359 | target: me.el, | |
360 | trackMouse: true, | |
361 | dismissDelay: 0, | |
362 | renderTo: Ext.getBody(), | |
f6710aac | 363 | html: me.data.text, |
95d0de89 DC |
364 | }); |
365 | } | |
366 | me.tooltip.show(); | |
f6710aac | 367 | }, |
95d0de89 DC |
368 | }, |
369 | mouseleave: { | |
370 | element: 'el', | |
371 | fn: function(events, element) { | |
372 | var me = this.component; | |
373 | if (me.tooltip) { | |
374 | me.tooltip.destroy(); | |
375 | delete me.tooltip; | |
376 | } | |
f6710aac TL |
377 | }, |
378 | }, | |
379 | }, | |
95d0de89 | 380 | }); |