]>
Commit | Line | Data |
---|---|---|
a36deac4 DC |
1 | Ext.define('PVE.node.DiskList', { |
2 | extend: 'Ext.grid.GridPanel', | |
3 | alias: 'widget.pveNodeDiskList', | |
4 | emptyText: gettext('No Disks found'), | |
e19b93ec DC |
5 | stateful: true, |
6 | stateId: 'grid-node-disks', | |
a36deac4 DC |
7 | columns: [ |
8 | { | |
9 | header: gettext('Device'), | |
10 | width: 100, | |
11 | sortable: true, | |
12 | dataIndex: 'devpath' | |
13 | }, | |
14 | { | |
15 | header: gettext('Type'), | |
16 | width: 80, | |
17 | sortable: true, | |
18 | dataIndex: 'type', | |
19 | renderer: function(v) { | |
20 | if (v === 'ssd') { | |
21 | return 'SSD'; | |
22 | } else if (v === 'hdd') { | |
23 | return 'Hard Disk'; | |
24 | } else if (v === 'usb'){ | |
25 | return 'USB'; | |
26 | } else { | |
27 | return gettext('Unknown'); | |
28 | } | |
29 | } | |
30 | }, | |
31 | { | |
32 | header: gettext('Usage'), | |
33 | width: 80, | |
34 | sortable: false, | |
35 | renderer: function(v, metaData, rec) { | |
36 | if (rec && (rec.data.osdid >= 0)) { | |
37 | return "osd." + rec.data.osdid.toString(); | |
38 | } | |
39 | return v || PVE.Utils.noText; | |
40 | }, | |
41 | dataIndex: 'used' | |
42 | }, | |
43 | { | |
44 | header: gettext('Size'), | |
45 | width: 100, | |
46 | align: 'right', | |
47 | sortable: true, | |
48 | renderer: PVE.Utils.format_size, | |
49 | dataIndex: 'size' | |
50 | }, | |
51 | { | |
52 | header: gettext('GPT'), | |
53 | width: 60, | |
54 | align: 'right', | |
55 | renderer: function(value) { | |
56 | if (value) { | |
57 | return PVE.Utils.yesText; | |
58 | } else { | |
59 | return PVE.Utils.noText; | |
60 | } | |
61 | }, | |
62 | dataIndex: 'gpt' | |
63 | }, | |
64 | { | |
65 | header: gettext('Vendor'), | |
66 | width: 100, | |
67 | sortable: true, | |
23280184 | 68 | renderer: Ext.String.htmlEncode, |
a36deac4 DC |
69 | dataIndex: 'vendor' |
70 | }, | |
71 | { | |
72 | header: gettext('Model'), | |
73 | width: 200, | |
74 | sortable: true, | |
23280184 | 75 | renderer: Ext.String.htmlEncode, |
a36deac4 DC |
76 | dataIndex: 'model' |
77 | }, | |
78 | { | |
79 | header: gettext('Serial'), | |
80 | width: 200, | |
81 | sortable: true, | |
23280184 | 82 | renderer: Ext.String.htmlEncode, |
a36deac4 DC |
83 | dataIndex: 'serial' |
84 | }, | |
85 | { | |
86 | header: 'S.M.A.R.T.', | |
87 | width: 100, | |
88 | sortable: true, | |
23280184 | 89 | renderer: Ext.String.htmlEncode, |
a36deac4 DC |
90 | dataIndex: 'health' |
91 | }, | |
92 | { | |
93 | header: 'Wearout', | |
94 | width: 100, | |
95 | sortable: true, | |
96 | dataIndex: 'wearout', | |
97 | renderer: function(value) { | |
98 | if (Ext.isNumeric(value)) { | |
99 | return (100 - value).toString() + '%'; | |
100 | } | |
101 | return 'N/A'; | |
102 | } | |
103 | } | |
104 | ], | |
105 | ||
106 | initComponent: function() { | |
107 | /*jslint confusion: true */ | |
108 | var me = this; | |
109 | ||
110 | var nodename = me.pveSelNode.data.node; | |
111 | if (!nodename) { | |
112 | throw "no node name specified"; | |
113 | } | |
114 | ||
115 | var sm = Ext.create('Ext.selection.RowModel', {}); | |
116 | ||
117 | var store = Ext.create('Ext.data.Store', { | |
118 | storeid: 'node-disk-list' + nodename, | |
119 | model: 'node-disk-list', | |
120 | proxy: { | |
121 | type: 'pve', | |
122 | url: "/api2/json/nodes/" + nodename + "/disks/list" | |
123 | }, | |
124 | sorters: [ | |
125 | { | |
126 | property : 'dev', | |
127 | direction: 'ASC' | |
128 | } | |
129 | ] | |
130 | }); | |
131 | ||
132 | var reloadButton = Ext.create('PVE.button.Button', { | |
133 | text: gettext('Reload'), | |
134 | handler: function() { | |
135 | me.store.load(); | |
136 | } | |
137 | }); | |
138 | ||
139 | var smartButton = Ext.create('PVE.button.Button', { | |
140 | text: gettext('Show S.M.A.R.T. values'), | |
141 | selModel: sm, | |
142 | enableFn: function() { | |
143 | return !!sm.getSelection().length; | |
144 | }, | |
145 | disabled: true, | |
146 | handler: function() { | |
147 | var rec = sm.getSelection()[0]; | |
148 | ||
149 | var win = Ext.create('PVE.DiskSmartWindow', { | |
150 | nodename: nodename, | |
151 | dev: rec.data.devpath | |
152 | }); | |
153 | win.show(); | |
154 | } | |
155 | }); | |
156 | ||
157 | var initButton = Ext.create('PVE.button.Button', { | |
158 | text: gettext('Initialize Disk with GPT'), | |
159 | selModel: sm, | |
160 | enableFn: function() { | |
161 | var selection = sm.getSelection(); | |
162 | ||
163 | if (!selection.length || selection[0].data.used) { | |
164 | return false; | |
165 | } else { | |
166 | return true; | |
167 | } | |
168 | }, | |
169 | disabled: true, | |
170 | ||
171 | handler: function() { | |
172 | var rec = sm.getSelection()[0]; | |
173 | PVE.Utils.API2Request({ | |
174 | url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt', | |
175 | waitMsgTarget: me, | |
176 | method: 'POST', | |
177 | params: { disk: rec.data.devpath}, | |
178 | failure: function(response, options) { | |
179 | Ext.Msg.alert(gettext('Error'), response.htmlStatus); | |
180 | }, | |
181 | success: function(response, options) { | |
182 | var upid = response.result.data; | |
183 | var win = Ext.create('PVE.window.TaskProgress', { | |
184 | upid: upid | |
185 | }); | |
186 | win.show(); | |
187 | } | |
188 | }); | |
189 | } | |
190 | }); | |
191 | ||
2149db2a DC |
192 | me.loadCount = 1; // avoid duplicate loadmask |
193 | PVE.Utils.monStoreErrors(me, store); | |
194 | ||
a36deac4 | 195 | Ext.apply(me, { |
a36deac4 DC |
196 | store: store, |
197 | selModel: sm, | |
a36deac4 DC |
198 | tbar: [ reloadButton, smartButton, initButton ], |
199 | listeners: { | |
200 | itemdblclick: function() { | |
201 | var rec = sm.getSelection()[0]; | |
202 | ||
203 | var win = Ext.create('PVE.DiskSmartWindow', { | |
204 | nodename: nodename, | |
205 | dev: rec.data.devpath | |
206 | }); | |
207 | win.show(); | |
208 | } | |
209 | } | |
210 | }); | |
211 | ||
212 | ||
213 | me.callParent(); | |
214 | me.store.load(); | |
215 | } | |
216 | }, function() { | |
217 | ||
218 | Ext.define('node-disk-list', { | |
219 | extend: 'Ext.data.Model', | |
220 | fields: [ 'devpath', 'used', { name: 'size', type: 'number'}, | |
221 | {name: 'osdid', type: 'number'}, | |
222 | 'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ], | |
223 | idProperty: 'devpath' | |
224 | }); | |
225 | }); | |
226 | ||
227 | Ext.define('PVE.DiskSmartWindow', { | |
228 | extend: 'Ext.window.Window', | |
229 | alias: 'widget.pveSmartWindow', | |
230 | ||
231 | modal: true, | |
232 | ||
233 | items: [ | |
234 | { | |
235 | xtype: 'gridpanel', | |
236 | layout: { | |
237 | type: 'fit' | |
238 | }, | |
239 | emptyText: gettext('No S.M.A.R.T. Values'), | |
240 | scrollable: true, | |
241 | flex: 1, | |
242 | itemId: 'smarts', | |
243 | reserveScrollbar: true, | |
244 | columns: [ | |
245 | { text: 'ID', dataIndex: 'id', width: 50 }, | |
23280184 DC |
246 | { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode }, |
247 | { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode }, | |
a36deac4 DC |
248 | { text: gettext('Normalized'), dataIndex: 'value', width: 60}, |
249 | { text: gettext('Threshold'), dataIndex: 'threshold', width: 60}, | |
250 | { text: gettext('Worst'), dataIndex: 'worst', width: 60}, | |
251 | { text: gettext('Flags'), dataIndex: 'flags'}, | |
23280184 | 252 | { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode } |
a36deac4 | 253 | ] |
d96ac973 DC |
254 | }, |
255 | { | |
256 | xtype: 'component', | |
257 | itemId: 'text', | |
258 | layout: { | |
259 | type: 'fit' | |
260 | }, | |
261 | hidden: true, | |
262 | style: { | |
263 | 'background-color': 'white', | |
264 | 'white-space': 'pre', | |
265 | 'font-family': 'monospace' | |
266 | } | |
a36deac4 DC |
267 | } |
268 | ], | |
269 | ||
270 | buttons: [ | |
271 | { | |
272 | text: gettext('Reload'), | |
273 | name: 'reload', | |
274 | handler: function() { | |
275 | var me = this; | |
276 | me.up('window').store.reload(); | |
277 | } | |
278 | }, | |
279 | { | |
280 | text: gettext('Close'), | |
281 | name: 'close', | |
282 | handler: function() { | |
283 | var me = this; | |
284 | me.up('window').close(); | |
285 | } | |
286 | } | |
287 | ], | |
288 | ||
289 | layout: { | |
290 | type: 'vbox', | |
291 | align: 'stretch' | |
292 | }, | |
293 | width: 800, | |
294 | height: 500, | |
295 | minWidth: 600, | |
296 | minHeight: 400, | |
297 | bodyPadding: 5, | |
298 | title: gettext('S.M.A.R.T. Values'), | |
299 | ||
300 | initComponent: function() { | |
301 | var me = this; | |
302 | ||
303 | var nodename = me.nodename; | |
304 | if (!nodename) { | |
305 | throw "no node name specified"; | |
306 | } | |
307 | ||
308 | var dev = me.dev; | |
309 | if (!dev) { | |
310 | throw "no device specified"; | |
311 | } | |
312 | ||
313 | me.store = Ext.create('Ext.data.Store', { | |
2149db2a | 314 | model: 'disk-smart', |
a36deac4 DC |
315 | proxy: { |
316 | type: 'pve', | |
a36deac4 DC |
317 | url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev |
318 | } | |
319 | }); | |
320 | ||
321 | me.callParent(); | |
2149db2a | 322 | var grid = me.down('#smarts'); |
d96ac973 | 323 | var text = me.down('#text'); |
2149db2a DC |
324 | |
325 | PVE.Utils.monStoreErrors(grid, me.store); | |
326 | me.mon(me.store, 'load', function(s, records, success) { | |
327 | if (success && records.length > 0) { | |
328 | var rec = records[0]; | |
d96ac973 DC |
329 | switch (rec.data.type) { |
330 | case 'text': | |
331 | grid.setVisible(false); | |
332 | text.setVisible(true); | |
333 | text.setHtml(Ext.String.htmlEncode(rec.data.text)); | |
334 | break; | |
335 | default: | |
336 | // includes 'ata' | |
337 | // cannot use empty case because | |
338 | // of jslint | |
339 | grid.setVisible(true); | |
340 | text.setVisible(false); | |
341 | grid.setStore(rec.attributes()); | |
342 | break; | |
343 | } | |
2149db2a DC |
344 | } |
345 | }); | |
346 | ||
a36deac4 DC |
347 | me.store.load(); |
348 | } | |
349 | }, function() { | |
350 | ||
351 | Ext.define('disk-smart', { | |
352 | extend: 'Ext.data.Model', | |
353 | fields: [ | |
d96ac973 DC |
354 | { name:'health'}, |
355 | { name:'type'}, | |
356 | { name:'text'} | |
a36deac4 DC |
357 | ], |
358 | hasMany: {model: 'smart-attribute', name: 'attributes'} | |
359 | }); | |
360 | Ext.define('smart-attribute', { | |
361 | extend: 'Ext.data.Model', | |
362 | fields: [ | |
363 | { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw' | |
e62526ea | 364 | ] |
a36deac4 DC |
365 | }); |
366 | }); |