]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/StatusDetail.js
ceph dashboard: add missing summary/message access level
[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.summary.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].message.match(monnameregex);
118 if (found !== null) {
119 if (!monmsgs[found[1]]) {
120 monmsgs[found[1]] = [];
121 }
122 monmsgs[found[1]].push({
123 text: Ext.Array.reduce(value.detail, function(first, second) {
124 return first + '\n' + second.message;
125 }, ''),
126 severity: value.severity
127 });
128 }
129 }
130 });
131
132 // update osds counts
133
134 var total_osds = osdmap.osdmap.num_osds || 0;
135 var in_osds = osdmap.osdmap.num_in_osds || 0;
136 var up_osds = osdmap.osdmap.num_up_osds || 0;
137 var out_osds = total_osds - in_osds;
138 var down_osds = total_osds - up_osds;
139
140 var downout_osds = down_osds - downin_osds;
141 var upin_osds = in_osds - downin_osds;
142 var upout_osds = up_osds - upin_osds;
143 var osds = {
144 total: total_osds,
145 upin: upin_osds,
146 upout: upout_osds,
147 downin: downin_osds,
148 downout: downout_osds
149 };
150 me.getComponent('osds').update(osds);
151
152 // update the monitors
153 var mons = monmap.mons.sort(function(a,b) {
154 return (a.name < b.name)?-1:(a.name > b.name)?1:0;
155 });
156
157 var monContainer = me.getComponent('monitors');
158
159 var i;
160 for (i = 0; i < mons.length; i++) {
161 var monitor = monContainer.getComponent('mon.' + mons[i].name);
162 if (!monitor) {
163 // since mons are already sorted, and
164 // we always have a sorted list
165 // we can add it at the mons+1 position (because of the title)
166 monitor = monContainer.insert(i+1, {
167 xtype: 'pveCephMonitorWidget',
168 itemId: 'mon.' + mons[i].name
169 });
170 }
171 monitor.updateMonitor(mons[i], monmsgs, quorum_names);
172 }
173 me.suspendLayout = false;
174 me.updateLayout();
175 }
176 });
177
178 Ext.define('PVE.ceph.MonitorWidget', {
179 extend: 'Ext.Component',
180 alias: 'widget.pveCephMonitorWidget',
181
182 userCls: 'monitor inline-block',
183 data: {
184 name: '0',
185 health: 'HEALTH_ERR',
186 text: '',
187 iconCls: PVE.Utils.get_health_icon(),
188 addr: ''
189 },
190
191 tpl: [
192 '{name}: ',
193 '<i class="fa fa-fw {iconCls}"></i>'
194 ],
195
196 // expects 3 variables which are
197 // timestate: the status from timechecks.mons
198 // data: the monmap.mons data
199 // quorum_names: the quorum_names array
200 updateMonitor: function(data, monmsgs, quorum_names) {
201 var me = this;
202 var state = 'HEALTH_ERR';
203 var text = '';
204 var healthstates = {
205 'HEALTH_OK': 3,
206 'HEALTH_WARN': 2,
207 'HEALTH_ERR': 1
208 };
209
210 if (quorum_names &&
211 quorum_names.indexOf(data.name) !== -1) {
212 state = 'HEALTH_OK';
213 }
214
215 if (monmsgs[data.name]) {
216 Ext.Array.forEach(monmsgs[data.name], function(msg) {
217 if (healthstates[msg.severity] < healthstates[state]) {
218 state = msg.severity;
219 }
220
221 text += msg.text + "\n";
222 });
223 }
224
225 me.update(Ext.apply(me.data, {
226 health: state,
227 text: text,
228 addr: data.addr,
229 name: data.name,
230 iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
231 }));
232 },
233
234 listeners: {
235 mouseenter: {
236 element: 'el',
237 fn: function(events, element) {
238 var me = this.component;
239 if (!me) {
240 return;
241 }
242 if (!me.tooltip) {
243 me.tooltip = Ext.create('Ext.tip.ToolTip', {
244 target: me.el,
245 trackMouse: true,
246 renderTo: Ext.getBody(),
247 html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
248 gettext('Address') + ': ' + me.data.addr + '<br />' +
249 gettext('Health') + ': ' + me.data.health + '<br />' +
250 me.data.text
251 });
252 }
253 me.tooltip.show();
254 }
255 },
256 mouseleave: {
257 element: 'el',
258 fn: function(events, element) {
259 var me = this.component;
260 if (me.tooltip) {
261 me.tooltip.destroy();
262 delete me.tooltip;
263 }
264 }
265 }
266 }
267 });