]>
Commit | Line | Data |
---|---|---|
bd39c945 | 1 | Ext.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 | ||
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 | |
e932cd5f DC |
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, | |
bf6e58d2 | 83 | modal: true, |
e932cd5f DC |
84 | width: 650, |
85 | height: 400, | |
86 | layout: { | |
87 | type: 'fit' | |
88 | }, | |
89 | items: [{ | |
90 | scrollable: true, | |
91 | padding: '10', | |
92 | xtype: 'box', | |
b01e7f7a DC |
93 | html: [ |
94 | '<span>' + Ext.htmlEncode(record.data.summary) + '</span>', | |
95 | '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>' | |
96 | ] | |
e932cd5f DC |
97 | }] |
98 | }); | |
99 | win.show(); | |
100 | } | |
101 | } | |
102 | ] | |
946730cd DC |
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, | |
2ce6111f | 152 | title: 'IOPS', // do not localize |
946730cd DC |
153 | renderer: Ext.util.Format.numberRenderer('0,000') |
154 | }, | |
155 | { | |
156 | itemId: 'readiops', | |
157 | xtype: 'pveRunningChart', | |
158 | hidden: true, | |
8f8ec25d | 159 | title: 'IOPS: ' + gettext('Reads'), |
946730cd DC |
160 | renderer: Ext.util.Format.numberRenderer('0,000') |
161 | }, | |
162 | { | |
163 | itemId: 'writeiops', | |
164 | xtype: 'pveRunningChart', | |
165 | hidden: true, | |
8f8ec25d | 166 | title: 'IOPS: ' + gettext('Writes'), |
946730cd DC |
167 | renderer: Ext.util.Format.numberRenderer('0,000') |
168 | } | |
169 | ] | |
170 | } | |
171 | ] | |
bd39c945 | 172 | } |
946730cd | 173 | ], |
bd39c945 | 174 | |
e932cd5f DC |
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, | |
37f01f69 DC |
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 | ), | |
e932cd5f DC |
192 | severity: checks[key].severity |
193 | }); | |
194 | }); | |
195 | ||
196 | return result; | |
197 | }, | |
198 | ||
946730cd DC |
199 | updateAll: function(store, records, success) { |
200 | if (!success || records.length === 0) { | |
201 | return; | |
202 | } | |
bd39c945 | 203 | |
946730cd DC |
204 | var me = this; |
205 | var rec = records[0]; | |
bd39c945 | 206 | |
946730cd | 207 | // add health panel |
dfe6d184 | 208 | me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {})); |
946730cd | 209 | // add errors to gridstore |
e932cd5f | 210 | me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false); |
bd39c945 | 211 | |
946730cd | 212 | // update detailstatus panel |
4a0bb017 DC |
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 || []); | |
bd39c945 | 219 | |
946730cd DC |
220 | // add performance data |
221 | var used = rec.data.pgmap.bytes_used; | |
222 | var total = rec.data.pgmap.bytes_total; | |
bd39c945 | 223 | |
946730cd DC |
224 | var text = Ext.String.format(gettext('{0} of {1}'), |
225 | PVE.Utils.render_size(used), | |
226 | PVE.Utils.render_size(total) | |
227 | ); | |
bd39c945 | 228 | |
946730cd DC |
229 | // update the usage widget |
230 | me.down('#space').updateValue(used/total, text); | |
bd39c945 | 231 | |
946730cd | 232 | // TODO: logic for jewel (iops splitted in read/write) |
bd39c945 | 233 | |
946730cd DC |
234 | var iops = rec.data.pgmap.op_per_sec; |
235 | var readiops = rec.data.pgmap.read_op_per_sec; | |
6783a330 | 236 | var writeiops = rec.data.pgmap.write_op_per_sec; |
946730cd DC |
237 | var reads = rec.data.pgmap.read_bytes_sec || 0; |
238 | var writes = rec.data.pgmap.write_bytes_sec || 0; | |
bd39c945 | 239 | |
946730cd DC |
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 | }, | |
bd39c945 | 261 | |
946730cd DC |
262 | initComponent: function() { |
263 | var me = this; | |
bd39c945 | 264 | |
946730cd DC |
265 | var nodename = me.pveSelNode.data.node; |
266 | if (!nodename) { | |
267 | throw "no node name specified"; | |
268 | } | |
bd39c945 | 269 | |
946730cd | 270 | me.callParent(); |
0c7c0d6b | 271 | me.store = Ext.create('Proxmox.data.UpdateStore', { |
946730cd DC |
272 | storeid: 'ceph-status-' + nodename, |
273 | interval: 5000, | |
274 | proxy: { | |
56a353b9 | 275 | type: 'proxmox', |
946730cd | 276 | url: '/api2/json/nodes/' + nodename + '/ceph/status' |
bd39c945 DM |
277 | } |
278 | }); | |
279 | ||
946730cd DC |
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 | ||
e7ade592 | 292 | Proxmox.Utils.monStoreErrors(me,me.store); |
946730cd DC |
293 | me.mon(me.store, 'load', me.updateAll, me); |
294 | me.on('destroy', me.store.stopUpdate); | |
295 | me.store.startUpdate(); | |
bd39c945 | 296 | } |
946730cd | 297 | |
bd39c945 | 298 | }); |