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