]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/ceph/StatusDetail.js
Select OS Type after selecting the Installation Media
[pve-manager.git] / www / manager6 / ceph / StatusDetail.js
CommitLineData
195c7c8c
DC
1Ext.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 monitors: []
77 },
78 tpl: [
79 '<h3>' + gettext('PGs') + '</h3>',
80 '<tpl for="monitors">',
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(record) {
89 var me = this;
90 me.suspendLayout = true;
91
92 if (!record.data.pgmap ||
93 !record.data.osdmap ||
94 !record.data.osdmap.osdmap ||
95 !record.data.health ||
96 !record.data.health.timechecks ||
97 !record.data.monmap ||
f3f73cde
DC
98 !record.data.monmap.mons ||
99 !record.data.health.health ||
100 !record.data.health.health.health_services ||
101 !record.data.health.health.health_services[0]) {
195c7c8c
DC
102 // only continue if we have all the data
103 return;
104 }
105
106 // update pgs sorted
107 var pgs_by_state = record.data.pgmap.pgs_by_state || [];
108 pgs_by_state.sort(function(a,b){
109 return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
110 });
111 me.getComponent('pgs').update({monitors: pgs_by_state});
112
113 // update osds counts
114 // caution: this code is not the nicest,
115 // but since the status call only gives us
116 // the total, up and in value,
117 // we parse the health summary and look for the
118 // x/y in osds are down message
119 // to get the rest of the numbers
120 //
121 // the alternative would be to make a second api call,
122 // as soon as not all osds are up, but those are costly
123
124 var total_osds = record.data.osdmap.osdmap.num_osds || 0;
125 var in_osds = record.data.osdmap.osdmap.num_in_osds || 0;
126 var up_osds = record.data.osdmap.osdmap.num_up_osds || 0;
127 var out_osds = total_osds - in_osds;
128 var down_osds = total_osds - up_osds;
129 var downin_osds = 0;
130 var downinregex = /(\d+)\/(\d+) in osds are down/;
131 Ext.Array.some(record.data.health.summary, function(item) {
132 var found = item.summary.match(downinregex);
133
134 if (found !== null) {
135 // sanity check, test if the message is
136 // consistent with the direct value
137 // for in osds
138 if (found[2] == in_osds) {
139 downin_osds = parseInt(found[1],10);
140 return true;
141 }
142 }
143
144 return false;
145 });
146
147 var downout_osds = down_osds - downin_osds;
148 var upin_osds = in_osds - downin_osds;
149 var upout_osds = up_osds - upin_osds;
150 var osds = {
151 total: total_osds,
152 upin: upin_osds,
153 upout: upout_osds,
154 downin: downin_osds,
155 downout: downout_osds
156 };
157 me.getComponent('osds').update(osds);
158
159 // update the monitors
160 var mons = record.data.monmap.mons.sort(function(a,b) {
161 return (a.name < b.name)?-1:(a.name > b.name)?1:0;
162 });
163
5c38487d 164 var monTimes = record.data.health.timechecks.mons || [];
f3f73cde 165 var monHealth = record.data.health.health.health_services[0].mons || [];
195c7c8c 166 var timechecks = {};
f3f73cde 167 var healthchecks = {};
195c7c8c
DC
168 var monContainer = me.getComponent('monitors');
169 var i;
170 for (i = 0; i < mons.length && i < monTimes.length; i++) {
171 timechecks[monTimes[i].name] = monTimes[i].health;
172 }
173
bd8950b0
DC
174 if (mons.length === 1) {
175 timechecks[mons[0].name] = "HEALTH_OK";
176 }
177
f3f73cde
DC
178 for (i = 0; i < mons.length && i < monHealth.length; i++) {
179 healthchecks[monHealth[i].name] = monHealth[i].health;
180 }
181
195c7c8c
DC
182 for (i = 0; i < mons.length; i++) {
183 var monitor = monContainer.getComponent('mon.' + mons[i].name);
184 if (!monitor) {
185 // since mons are already sorted, and
186 // we always have a sorted list
187 // we can add it at the mons+1 position (because of the title)
188 monitor = monContainer.insert(i+1, {
189 xtype: 'pveCephMonitorWidget',
190 itemId: 'mon.' + mons[i].name
191 });
192 }
f3f73cde 193 monitor.updateMonitor(timechecks[mons[i].name], mons[i], record.data.quorum_names, healthchecks[mons[i].name]);
195c7c8c
DC
194 }
195 me.suspendLayout = false;
196 me.updateLayout();
197 }
198});
199
200Ext.define('PVE.ceph.MonitorWidget', {
201 extend: 'Ext.Component',
202 alias: 'widget.pveCephMonitorWidget',
203
204 userCls: 'monitor inline-block',
205 data: {
206 name: '0',
207 health: 'HEALTH_ERR',
208 iconCls: PVE.Utils.get_health_icon(),
209 addr: ''
210 },
211
212 tpl: [
213 '{name}: ',
214 '<i class="fa fa-fw {iconCls}"></i>'
215 ],
216
217 // expects 3 variables which are
218 // timestate: the status from timechecks.mons
219 // data: the monmap.mons data
220 // quorum_names: the quorum_names array
f3f73cde 221 updateMonitor: function(timestate, data, quorum_names, health) {
195c7c8c
DC
222 var me = this;
223 var state = 'HEALTH_ERR';
f3f73cde
DC
224 var healthstates = {
225 'HEALTH_OK': 3,
226 'HEALTH_WARN': 2,
227 'HEALTH_ERR': 1
228 };
195c7c8c
DC
229
230 // if the monitor is part of the quorum
231 // and has a timestate, get the timestate,
232 // otherwise the state is ERR
f3f73cde 233 if (timestate && health && quorum_names &&
195c7c8c 234 quorum_names.indexOf(data.name) !== -1) {
f3f73cde
DC
235 state = (healthstates[health] < healthstates[timestate])?
236 health : timestate;
195c7c8c
DC
237 }
238
239 me.update(Ext.apply(me.data, {
240 health: state,
241 addr: data.addr,
242 name: data.name,
243 iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
244 }));
245 },
246
247 listeners: {
248 mouseenter: {
249 element: 'el',
250 fn: function(events, element) {
251 var me = this.component;
252 if (!me) {
253 return;
254 }
255 if (!me.tooltip) {
256 me.tooltip = Ext.create('Ext.tip.ToolTip', {
257 target: me.el,
258 trackMouse: true,
259 renderTo: Ext.getBody(),
260 html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
261 gettext('Address') + ': ' + me.data.addr + '<br />' +
262 gettext('Health') + ': ' + me.data.health
263 });
264 }
265 me.tooltip.show();
266 }
267 },
268 mouseleave: {
269 element: 'el',
270 fn: function(events, element) {
271 var me = this.component;
272 if (me.tooltip) {
273 me.tooltip.hide();
274 }
275 }
276 }
277 }
278});