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