]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/ceph/Status.js
buildsys: www/manager: all target needs to be first one
[pve-manager.git] / www / manager6 / ceph / Status.js
CommitLineData
bd39c945 1Ext.define('PVE.node.CephStatus', {
946730cd
DC
2 extend: 'Ext.panel.Panel',
3 alias: 'widget.pveNodeCephStatus',
4
ba93a9c6 5 onlineHelp: 'chapter_pveceph',
bd39c945 6
946730cd
DC
7 scrollable: true,
8
9f7cbaf3
DC
9 bodyPadding: 5,
10
11 layout: {
12 type: 'column'
13 },
946730cd
DC
14
15 defaults: {
9f7cbaf3 16 padding: 5
946730cd
DC
17 },
18
19 items: [
20 {
21 xtype: 'panel',
22 title: gettext('Health'),
9f7cbaf3
DC
23 bodyPadding: 10,
24 plugins: 'responsive',
25 responsiveConfig: {
26 'width < 1900': {
27b91275 27 minHeight: 230,
9f7cbaf3
DC
28 columnWidth: 1
29 },
30 'width >= 1900': {
27b91275 31 minHeight: 500,
9f7cbaf3
DC
32 columnWidth: 0.5
33 }
34 },
946730cd
DC
35 layout: {
36 type: 'hbox',
9f7cbaf3 37 align: 'stretch'
946730cd
DC
38 },
39 items: [
40 {
949a6609
DC
41 xtype: 'container',
42 layout: {
43 type: 'vbox',
44 align: 'stretch',
45 },
946730cd 46 flex: 1,
949a6609
DC
47 items: [
48 {
49 flex: 1,
50 itemId: 'overallhealth',
51 xtype: 'pveHealthWidget',
52 title: gettext('Status')
53 },
54 {
55 itemId: 'versioninfo',
0beb2578
TL
56 xtype: 'displayfield',
57 fieldLabel: gettext('Ceph Version'),
58 value: "",
59 autoEl: {
60 tag: 'div',
61 'data-qtip': gettext('The newest version installed in the Cluster.'),
949a6609
DC
62 },
63 padding: '10 0 0 0',
64 style: {
65 'text-align': 'center',
66 },
949a6609 67 }
0beb2578 68 ],
946730cd
DC
69 },
70 {
71 flex: 2,
72 itemId: 'warnings',
73 stateful: true,
74 stateId: 'ceph-status-warnings',
946730cd 75 xtype: 'grid',
23f14fd9
TL
76 // since we load the store manually to show the emptytext,
77 // we have to specify an empty one here
78 store: {
79 data: [],
80 },
946730cd
DC
81 emptyText: gettext('No Warnings/Errors'),
82 columns: [
83 {
84 dataIndex: 'severity',
85 header: gettext('Severity'),
86 align: 'center',
87 width: 70,
88 renderer: function(value) {
89 var health = PVE.Utils.map_ceph_health[value];
90 var classes = PVE.Utils.get_health_icon(health);
91
92 return '<i class="fa fa-fw ' + classes + '"></i>';
93 },
94 sorter: {
95 sorterFn: function(a,b) {
96 var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
97 return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
98 }
99 }
100 },
101 {
102 dataIndex: 'summary',
103 header: gettext('Summary'),
104 flex: 1
e932cd5f
DC
105 },
106 {
107 xtype: 'actioncolumn',
108 width: 40,
109 align: 'center',
110 tooltip: gettext('Detail'),
111 items: [
112 {
113 iconCls: 'x-fa fa-info-circle',
114 handler: function(grid, rowindex, colindex, item, e, record) {
115 var win = Ext.create('Ext.window.Window', {
116 title: gettext('Detail'),
117 resizable: true,
bf6e58d2 118 modal: true,
e932cd5f
DC
119 width: 650,
120 height: 400,
121 layout: {
122 type: 'fit'
123 },
124 items: [{
125 scrollable: true,
9f7cbaf3 126 padding: 10,
e932cd5f 127 xtype: 'box',
b01e7f7a
DC
128 html: [
129 '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
130 '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
131 ]
e932cd5f
DC
132 }]
133 });
134 win.show();
135 }
136 }
137 ]
946730cd
DC
138 }
139 ]
140 }
141 ]
142 },
143 {
144 xtype: 'pveCephStatusDetail',
145 itemId: 'statusdetail',
9f7cbaf3
DC
146 plugins: 'responsive',
147 responsiveConfig: {
148 'width < 1900': {
27b91275
DC
149 columnWidth: 1,
150 minHeight: 250
9f7cbaf3
DC
151 },
152 'width >= 1900': {
27b91275
DC
153 columnWidth: 0.5,
154 minHeight: 300
9f7cbaf3
DC
155 }
156 },
946730cd
DC
157 title: gettext('Status')
158 },
4ad4262d
DC
159 {
160 title: gettext('Services'),
161 xtype: 'pveCephServices',
162 itemId: 'services',
163 plugins: 'responsive',
164 layout: {
165 type: 'hbox',
166 align: 'stretch'
167 },
168 responsiveConfig: {
169 'width < 1900': {
170 columnWidth: 1,
171 minHeight: 200
172 },
173 'width >= 1900': {
174 columnWidth: 0.5,
175 minHeight: 200
176 }
177 }
178 },
946730cd
DC
179 {
180 xtype: 'panel',
181 title: gettext('Performance'),
9f7cbaf3
DC
182 columnWidth: 1,
183 bodyPadding: 5,
946730cd
DC
184 layout: {
185 type: 'hbox',
186 align: 'center'
187 },
188 items: [
189 {
190 flex: 1,
5683fb60 191 xtype: 'proxmoxGauge',
946730cd
DC
192 itemId: 'space',
193 title: gettext('Usage')
194 },
195 {
196 flex: 2,
197 xtype: 'container',
198 defaults: {
9f7cbaf3 199 padding: 0,
946730cd
DC
200 height: 100
201 },
202 items: [
203 {
204 itemId: 'reads',
205 xtype: 'pveRunningChart',
206 title: gettext('Reads'),
207 renderer: PVE.Utils.render_bandwidth
208 },
209 {
210 itemId: 'writes',
211 xtype: 'pveRunningChart',
212 title: gettext('Writes'),
213 renderer: PVE.Utils.render_bandwidth
214 },
946730cd
DC
215 {
216 itemId: 'readiops',
217 xtype: 'pveRunningChart',
8f8ec25d 218 title: 'IOPS: ' + gettext('Reads'),
946730cd
DC
219 renderer: Ext.util.Format.numberRenderer('0,000')
220 },
221 {
222 itemId: 'writeiops',
223 xtype: 'pveRunningChart',
8f8ec25d 224 title: 'IOPS: ' + gettext('Writes'),
946730cd 225 renderer: Ext.util.Format.numberRenderer('0,000')
df503ff9 226 },
946730cd
DC
227 ]
228 }
229 ]
bd39c945 230 }
946730cd 231 ],
bd39c945 232
e932cd5f
DC
233 generateCheckData: function(health) {
234 var result = [];
235 var checks = health.checks || {};
236 var keys = Ext.Object.getKeys(checks).sort();
237
238 Ext.Array.forEach(keys, function(key) {
239 var details = checks[key].detail || [];
240 result.push({
241 id: key,
37f01f69
DC
242 summary: checks[key].summary.message,
243 detail: Ext.Array.reduce(
244 checks[key].detail,
245 function(first, second) {
246 return first + '\n' + second.message;
247 },
248 ''
249 ),
e932cd5f
DC
250 severity: checks[key].severity
251 });
252 });
253
254 return result;
255 },
256
946730cd
DC
257 updateAll: function(store, records, success) {
258 if (!success || records.length === 0) {
259 return;
260 }
bd39c945 261
946730cd
DC
262 var me = this;
263 var rec = records[0];
0bf3c581 264 me.status = rec.data;
bd39c945 265
946730cd 266 // add health panel
dfe6d184 267 me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
946730cd 268 // add errors to gridstore
e932cd5f 269 me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
bd39c945 270
4ad4262d
DC
271 // update services
272 me.getComponent('services').updateAll(me.metadata || {}, rec.data);
273
946730cd 274 // update detailstatus panel
0bf3c581 275 me.getComponent('statusdetail').updateAll(me.metadata || {}, rec.data);
bd39c945 276
946730cd 277 // add performance data
df503ff9
TL
278 let pgmap = rec.data.pgmap;
279 let used = pgmap.bytes_used;
280 let total = pgmap.bytes_total;
bd39c945 281
946730cd
DC
282 var text = Ext.String.format(gettext('{0} of {1}'),
283 PVE.Utils.render_size(used),
284 PVE.Utils.render_size(total)
285 );
bd39c945 286
946730cd
DC
287 // update the usage widget
288 me.down('#space').updateValue(used/total, text);
bd39c945 289
df503ff9
TL
290 let readiops = pgmap.read_op_per_sec;
291 let writeiops = pgmap.write_op_per_sec;
292 let reads = pgmap.read_bytes_sec || 0;
293 let writes = pgmap.write_bytes_sec || 0;
bd39c945 294
946730cd
DC
295 // update the graphs
296 me.reads.addDataPoint(reads);
297 me.writes.addDataPoint(writes);
946730cd
DC
298 me.readiops.addDataPoint(readiops);
299 me.writeiops.addDataPoint(writeiops);
300 },
301
946730cd
DC
302 initComponent: function() {
303 var me = this;
bd39c945 304
946730cd 305 var nodename = me.pveSelNode.data.node;
bd39c945 306
946730cd 307 me.callParent();
d2193664 308 var baseurl = '/api2/json' + (nodename ? '/nodes/' + nodename : '/cluster') + '/ceph';
0c7c0d6b 309 me.store = Ext.create('Proxmox.data.UpdateStore', {
2365c5c1 310 storeid: 'ceph-status-' + (nodename || 'cluster'),
946730cd
DC
311 interval: 5000,
312 proxy: {
56a353b9 313 type: 'proxmox',
2365c5c1 314 url: baseurl + '/status'
bd39c945
DM
315 }
316 });
317
7f58689d
DC
318 me.metadatastore = Ext.create('Proxmox.data.UpdateStore', {
319 storeid: 'ceph-metadata-' + (nodename || 'cluster'),
320 interval: 15*1000,
321 proxy: {
322 type: 'proxmox',
44dde2cb 323 url: '/api2/json/cluster/ceph/metadata'
7f58689d
DC
324 }
325 });
326
946730cd
DC
327 // save references for the updatefunction
328 me.iops = me.down('#iops');
329 me.readiops = me.down('#readiops');
330 me.writeiops = me.down('#writeiops');
331 me.reads = me.down('#reads');
332 me.writes = me.down('#writes');
333
4616a55b
TM
334 var regex = new RegExp("not (installed|initialized)", "i");
335 PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
336 me.store.stopUpdate();
2365c5c1 337 PVE.Utils.showCephInstallOrMask(me, error.statusText, (nodename || 'localhost'),
4616a55b
TM
338 function(win){
339 me.mon(win, 'cephInstallWindowClosed', function(){
340 me.store.startUpdate();
341 });
342 }
343 );
344 });
345
946730cd 346 me.mon(me.store, 'load', me.updateAll, me);
7f58689d
DC
347 me.mon(me.metadatastore, 'load', function(store, records, success) {
348 if (!success || records.length < 1) {
349 return;
350 }
351 var rec = records[0];
352 me.metadata = rec.data;
353
4ad4262d
DC
354 // update services
355 me.getComponent('services').updateAll(rec.data, me.status || {});
356
7f58689d
DC
357 // update detailstatus panel
358 me.getComponent('statusdetail').updateAll(rec.data, me.status || {});
359
949a6609
DC
360 let maxversion = [];
361 let maxversiontext = "";
949a6609
DC
362 for (const [nodename, data] of Object.entries(me.metadata.node)) {
363 let version = data.version.parts;
364 if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
365 maxversion = version;
949a6609
DC
366 maxversiontext = data.version.str;
367 }
368 }
0beb2578 369 me.down('#versioninfo').setValue(maxversiontext);
7f58689d
DC
370 }, me);
371
946730cd 372 me.on('destroy', me.store.stopUpdate);
4ad4262d 373 me.on('destroy', me.metadatastore.stopUpdate);
946730cd 374 me.store.startUpdate();
4ad4262d 375 me.metadatastore.startUpdate();
bd39c945 376 }
946730cd 377
bd39c945 378});