]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/Status.js
use Proxmox.Utils instead of PVE.Utils
[pve-manager.git] / www / manager6 / ceph / Status.js
1 Ext.define('PVE.node.CephStatus', {
2 extend: 'Ext.panel.Panel',
3 alias: 'widget.pveNodeCephStatus',
4
5 onlineHelp: 'chapter_pveceph',
6
7 scrollable: true,
8
9 bodyPadding: '10 0 0 0',
10
11 defaults: {
12 width: 762,
13 userCls: 'inline-block',
14 padding: '0 0 10 10'
15 },
16
17 items: [
18 {
19 xtype: 'panel',
20 title: gettext('Health'),
21 bodyPadding: '0 10 10 10',
22 minHeight: 210,
23 layout: {
24 type: 'hbox',
25 align: 'top'
26 },
27 items: [
28 {
29 flex: 1,
30 itemId: 'overallhealth',
31 xtype: 'pveHealthWidget',
32 title: gettext('Status')
33 },
34 {
35 flex: 2,
36 itemId: 'warnings',
37 stateful: true,
38 stateId: 'ceph-status-warnings',
39 padding: '15 0 0 0',
40 xtype: 'grid',
41 minHeight: 100,
42 // since we load the store manually,
43 // to show the emptytext, we have to
44 // specify an empty store
45 store: { data:[] },
46 emptyText: gettext('No Warnings/Errors'),
47 columns: [
48 {
49 dataIndex: 'severity',
50 header: gettext('Severity'),
51 align: 'center',
52 width: 70,
53 renderer: function(value) {
54 var health = PVE.Utils.map_ceph_health[value];
55 var classes = PVE.Utils.get_health_icon(health);
56
57 return '<i class="fa fa-fw ' + classes + '"></i>';
58 },
59 sorter: {
60 sorterFn: function(a,b) {
61 var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
62 return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
63 }
64 }
65 },
66 {
67 dataIndex: 'summary',
68 header: gettext('Summary'),
69 flex: 1
70 },
71 {
72 xtype: 'actioncolumn',
73 width: 40,
74 align: 'center',
75 tooltip: gettext('Detail'),
76 items: [
77 {
78 iconCls: 'x-fa fa-info-circle',
79 handler: function(grid, rowindex, colindex, item, e, record) {
80 var win = Ext.create('Ext.window.Window', {
81 title: gettext('Detail'),
82 resizable: true,
83 modal: true,
84 width: 650,
85 height: 400,
86 layout: {
87 type: 'fit'
88 },
89 items: [{
90 scrollable: true,
91 padding: '10',
92 xtype: 'box',
93 html: [
94 '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
95 '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
96 ]
97 }]
98 });
99 win.show();
100 }
101 }
102 ]
103 }
104 ]
105 }
106 ]
107 },
108 {
109 xtype: 'pveCephStatusDetail',
110 itemId: 'statusdetail',
111 title: gettext('Status')
112 },
113 {
114 xtype: 'panel',
115 title: gettext('Performance'),
116 bodyPadding: '0 10 10 10',
117 layout: {
118 type: 'hbox',
119 align: 'center'
120 },
121 items: [
122 {
123 flex: 1,
124 xtype: 'pveGauge',
125 itemId: 'space',
126 title: gettext('Usage')
127 },
128 {
129 flex: 2,
130 xtype: 'container',
131 defaults: {
132 padding: '0 0 0 30',
133 height: 100
134 },
135 items: [
136 {
137 itemId: 'reads',
138 xtype: 'pveRunningChart',
139 title: gettext('Reads'),
140 renderer: PVE.Utils.render_bandwidth
141 },
142 {
143 itemId: 'writes',
144 xtype: 'pveRunningChart',
145 title: gettext('Writes'),
146 renderer: PVE.Utils.render_bandwidth
147 },
148 {
149 itemId: 'iops',
150 xtype: 'pveRunningChart',
151 hidden: true,
152 title: 'IOPS', // do not localize
153 renderer: Ext.util.Format.numberRenderer('0,000')
154 },
155 {
156 itemId: 'readiops',
157 xtype: 'pveRunningChart',
158 hidden: true,
159 title: 'IOPS: ' + gettext('Reads'),
160 renderer: Ext.util.Format.numberRenderer('0,000')
161 },
162 {
163 itemId: 'writeiops',
164 xtype: 'pveRunningChart',
165 hidden: true,
166 title: 'IOPS: ' + gettext('Writes'),
167 renderer: Ext.util.Format.numberRenderer('0,000')
168 }
169 ]
170 }
171 ]
172 }
173 ],
174
175 generateCheckData: function(health) {
176 var result = [];
177 var checks = health.checks || {};
178 var keys = Ext.Object.getKeys(checks).sort();
179
180 Ext.Array.forEach(keys, function(key) {
181 var details = checks[key].detail || [];
182 result.push({
183 id: key,
184 summary: checks[key].summary.message,
185 detail: Ext.Array.reduce(
186 checks[key].detail,
187 function(first, second) {
188 return first + '\n' + second.message;
189 },
190 ''
191 ),
192 severity: checks[key].severity
193 });
194 });
195
196 return result;
197 },
198
199 updateAll: function(store, records, success) {
200 if (!success || records.length === 0) {
201 return;
202 }
203
204 var me = this;
205 var rec = records[0];
206
207 // add health panel
208 me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
209 // add errors to gridstore
210 me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
211
212 // update detailstatus panel
213 me.getComponent('statusdetail').updateAll(
214 rec.data.health || {},
215 rec.data.monmap || {},
216 rec.data.pgmap || {},
217 rec.data.osdmap || {},
218 rec.data.quorum_names || []);
219
220 // add performance data
221 var used = rec.data.pgmap.bytes_used;
222 var total = rec.data.pgmap.bytes_total;
223
224 var text = Ext.String.format(gettext('{0} of {1}'),
225 PVE.Utils.render_size(used),
226 PVE.Utils.render_size(total)
227 );
228
229 // update the usage widget
230 me.down('#space').updateValue(used/total, text);
231
232 // TODO: logic for jewel (iops splitted in read/write)
233
234 var iops = rec.data.pgmap.op_per_sec;
235 var readiops = rec.data.pgmap.read_op_per_sec;
236 var writeiops = rec.data.pgmap.write_op_per_sec;
237 var reads = rec.data.pgmap.read_bytes_sec || 0;
238 var writes = rec.data.pgmap.write_bytes_sec || 0;
239
240 if (iops !== undefined && me.version !== 'hammer') {
241 me.change_version('hammer');
242 } else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
243 me.change_version('jewel');
244 }
245 // update the graphs
246 me.reads.addDataPoint(reads);
247 me.writes.addDataPoint(writes);
248 me.iops.addDataPoint(iops);
249 me.readiops.addDataPoint(readiops);
250 me.writeiops.addDataPoint(writeiops);
251 },
252
253 change_version: function(version) {
254 var me = this;
255 me.version = version;
256 me.sp.set('ceph-version', version);
257 me.iops.setVisible(version === 'hammer');
258 me.readiops.setVisible(version === 'jewel');
259 me.writeiops.setVisible(version === 'jewel');
260 },
261
262 initComponent: function() {
263 var me = this;
264
265 var nodename = me.pveSelNode.data.node;
266 if (!nodename) {
267 throw "no node name specified";
268 }
269
270 me.callParent();
271 me.store = Ext.create('Proxmox.data.UpdateStore', {
272 storeid: 'ceph-status-' + nodename,
273 interval: 5000,
274 proxy: {
275 type: 'pve',
276 url: '/api2/json/nodes/' + nodename + '/ceph/status'
277 }
278 });
279
280 // save references for the updatefunction
281 me.iops = me.down('#iops');
282 me.readiops = me.down('#readiops');
283 me.writeiops = me.down('#writeiops');
284 me.reads = me.down('#reads');
285 me.writes = me.down('#writes');
286
287 // get ceph version
288 me.sp = Ext.state.Manager.getProvider();
289 me.version = me.sp.get('ceph-version');
290 me.change_version(me.version);
291
292 Proxmox.Utils.monStoreErrors(me,me.store);
293 me.mon(me.store, 'load', me.updateAll, me);
294 me.on('destroy', me.store.stopUpdate);
295 me.store.startUpdate();
296 }
297
298 });