]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/StatusDetail.js
adapt ceph status detail to luminous and make it more robust
[pve-manager.git] / www / manager6 / ceph / StatusDetail.js
1 Ext.define('PVE.ceph.StatusDetail', {
2 extend: 'Ext.panel.Panel',
3 alias: 'widget.pveCephStatusDetail',
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 flex: 1,
20 itemId: 'monitors',
21 xtype: 'container',
22 items: [
23 {
24 xtype: 'box',
25 width: '100%',
26 html: '<h3>' + gettext('Monitors') + '</h3>'
27 }
28 ]
29 },{
30 flex: 1,
31 itemId: 'osds',
32 data: {
33 total: 0,
34 upin: 0,
35 upout: 0,
36 downin: 0,
37 downout: 0
38 },
39 tpl: [
40 '<h3>' + gettext('OSDs') + '</h3>',
41 '<table class="osds">',
42 '<tr><td></td>',
43 '<td><i class="fa fa-fw good fa-circle"></i>',
44 gettext('In'),
45 '</td>',
46 '<td><i class="fa fa-fw warning fa-circle-o"></i>',
47 gettext('Out'),
48 '</td>',
49 '</tr>',
50 '<tr>',
51 '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
52 gettext('Up'),
53 '</td>',
54 '<td>{upin}</td>',
55 '<td>{upout}</td>',
56 '</tr>',
57 '<tr>',
58 '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
59 gettext('Down'),
60 '</td>',
61 '<td>{downin}</td>',
62 '<td>{downout}</td>',
63 '</tr>',
64 '</table>',
65 '<br /><div>',
66 gettext('Total'),
67 ': {total}',
68 '</div>'
69 ]
70 },
71 {
72 flex: 1.6,
73 itemId: 'pgs',
74 padding: '0 10',
75 data: {
76 states: []
77 },
78 tpl: [
79 '<h3>' + gettext('PGs') + '</h3>',
80 '<tpl for="states">',
81 '<div class="left-aligned">{state_name}:</div>',
82 '<div class="right-aligned">{count}</div><br />',
83 '<div style="clear:both"></div>',
84 '</tpl>'
85 ]
86 }],
87
88 updateAll: function(health, monmap, pgmap, osdmap, quorum_names) {
89 var me = this;
90 me.suspendLayout = true;
91
92 // update pgs sorted
93 var pgs_by_state = pgmap.pgs_by_state || [];
94 pgs_by_state.sort(function(a,b){
95 return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
96 });
97 me.getComponent('pgs').update({states: pgs_by_state});
98
99 var downinregex = /(\d+) osds down/;
100 var monnameregex = /^mon.(\S+) /;
101 var downin_osds = 0;
102 var monmsgs = {};
103
104 // we collect monitor/osd information from the checks
105 Ext.Object.each(health.checks, function(key, value, obj) {
106 var found = null;
107 if (key === 'OSD_DOWN') {
108 found = value.message.match(downinregex);
109 if (found !== null) {
110 downin_osds = parseInt(found[1],10);
111 }
112 }
113 else if (Ext.String.startsWith(key, 'MON_')) {
114 if (!value.detail) {
115 return;
116 }
117 found = value.detail[0].match(monnameregex);
118 if (found !== null) {
119 if (!monmsgs[found[1]]) {
120 monmsgs[found[1]] = [];
121 }
122 monmsgs[found[1]].push({
123 text: value.detail.join("\n"),
124 severity: value.severity
125 });
126 }
127 }
128 });
129
130 // update osds counts
131
132 var total_osds = osdmap.osdmap.num_osds || 0;
133 var in_osds = osdmap.osdmap.num_in_osds || 0;
134 var up_osds = osdmap.osdmap.num_up_osds || 0;
135 var out_osds = total_osds - in_osds;
136 var down_osds = total_osds - up_osds;
137
138 var downout_osds = down_osds - downin_osds;
139 var upin_osds = in_osds - downin_osds;
140 var upout_osds = up_osds - upin_osds;
141 var osds = {
142 total: total_osds,
143 upin: upin_osds,
144 upout: upout_osds,
145 downin: downin_osds,
146 downout: downout_osds
147 };
148 me.getComponent('osds').update(osds);
149
150 // update the monitors
151 var mons = monmap.mons.sort(function(a,b) {
152 return (a.name < b.name)?-1:(a.name > b.name)?1:0;
153 });
154
155 var monContainer = me.getComponent('monitors');
156
157 var i;
158 for (i = 0; i < mons.length; i++) {
159 var monitor = monContainer.getComponent('mon.' + mons[i].name);
160 if (!monitor) {
161 // since mons are already sorted, and
162 // we always have a sorted list
163 // we can add it at the mons+1 position (because of the title)
164 monitor = monContainer.insert(i+1, {
165 xtype: 'pveCephMonitorWidget',
166 itemId: 'mon.' + mons[i].name
167 });
168 }
169 monitor.updateMonitor(mons[i], monmsgs, quorum_names);
170 }
171 me.suspendLayout = false;
172 me.updateLayout();
173 }
174 });
175
176 Ext.define('PVE.ceph.MonitorWidget', {
177 extend: 'Ext.Component',
178 alias: 'widget.pveCephMonitorWidget',
179
180 userCls: 'monitor inline-block',
181 data: {
182 name: '0',
183 health: 'HEALTH_ERR',
184 text: '',
185 iconCls: PVE.Utils.get_health_icon(),
186 addr: ''
187 },
188
189 tpl: [
190 '{name}: ',
191 '<i class="fa fa-fw {iconCls}"></i>'
192 ],
193
194 // expects 3 variables which are
195 // timestate: the status from timechecks.mons
196 // data: the monmap.mons data
197 // quorum_names: the quorum_names array
198 updateMonitor: function(data, monmsgs, quorum_names) {
199 var me = this;
200 var state = 'HEALTH_ERR';
201 var text = '';
202 var healthstates = {
203 'HEALTH_OK': 3,
204 'HEALTH_WARN': 2,
205 'HEALTH_ERR': 1
206 };
207
208 if (quorum_names &&
209 quorum_names.indexOf(data.name) !== -1) {
210 state = 'HEALTH_OK';
211 }
212
213 if (monmsgs[data.name]) {
214 Ext.Array.forEach(monmsgs[data.name], function(msg) {
215 if (healthstates[msg.severity] < healthstates[state]) {
216 state = msg.severity;
217 }
218
219 text += msg.text + "\n";
220 });
221 }
222
223 me.update(Ext.apply(me.data, {
224 health: state,
225 text: text,
226 addr: data.addr,
227 name: data.name,
228 iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
229 }));
230 },
231
232 listeners: {
233 mouseenter: {
234 element: 'el',
235 fn: function(events, element) {
236 var me = this.component;
237 if (!me) {
238 return;
239 }
240 if (!me.tooltip) {
241 me.tooltip = Ext.create('Ext.tip.ToolTip', {
242 target: me.el,
243 trackMouse: true,
244 renderTo: Ext.getBody(),
245 html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
246 gettext('Address') + ': ' + me.data.addr + '<br />' +
247 gettext('Health') + ': ' + me.data.health + '<br />' +
248 me.data.text
249 });
250 }
251 me.tooltip.show();
252 }
253 },
254 mouseleave: {
255 element: 'el',
256 fn: function(events, element) {
257 var me = this.component;
258 if (me.tooltip) {
259 me.tooltip.destroy();
260 delete me.tooltip;
261 }
262 }
263 }
264 }
265 });