Dominik Csapak 4f194bee43 show smart text if disk type is not ATA
in case the disk is not type ATA (e.g. SAS),
the smartctl output is not well parsable,
so we show the raw text instead

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
2016-10-05 06:53:57 +02:00

368 lines
7.8 KiB
JavaScript

Ext.define('PVE.node.DiskList', {
extend: 'Ext.grid.GridPanel',
alias: 'widget.pveNodeDiskList',
emptyText: gettext('No Disks found'),
columns: [
{
header: gettext('Device'),
width: 100,
sortable: true,
dataIndex: 'devpath'
},
{
header: gettext('Type'),
width: 80,
sortable: true,
dataIndex: 'type',
renderer: function(v) {
if (v === 'ssd') {
return 'SSD';
} else if (v === 'hdd') {
return 'Hard Disk';
} else if (v === 'usb'){
return 'USB';
} else {
return gettext('Unknown');
}
}
},
{
header: gettext('Usage'),
width: 80,
sortable: false,
renderer: function(v, metaData, rec) {
if (rec && (rec.data.osdid >= 0)) {
return "osd." + rec.data.osdid.toString();
}
return v || PVE.Utils.noText;
},
dataIndex: 'used'
},
{
header: gettext('Size'),
width: 100,
align: 'right',
sortable: true,
renderer: PVE.Utils.format_size,
dataIndex: 'size'
},
{
header: gettext('GPT'),
width: 60,
align: 'right',
renderer: function(value) {
if (value) {
return PVE.Utils.yesText;
} else {
return PVE.Utils.noText;
}
},
dataIndex: 'gpt'
},
{
header: gettext('Vendor'),
width: 100,
sortable: true,
renderer: Ext.String.htmlEncode,
dataIndex: 'vendor'
},
{
header: gettext('Model'),
width: 200,
sortable: true,
renderer: Ext.String.htmlEncode,
dataIndex: 'model'
},
{
header: gettext('Serial'),
width: 200,
sortable: true,
renderer: Ext.String.htmlEncode,
dataIndex: 'serial'
},
{
header: 'S.M.A.R.T.',
width: 100,
sortable: true,
renderer: Ext.String.htmlEncode,
dataIndex: 'health'
},
{
header: 'Wearout',
width: 100,
sortable: true,
dataIndex: 'wearout',
renderer: function(value) {
if (Ext.isNumeric(value)) {
return (100 - value).toString() + '%';
}
return 'N/A';
}
}
],
initComponent: function() {
/*jslint confusion: true */
var me = this;
var nodename = me.pveSelNode.data.node;
if (!nodename) {
throw "no node name specified";
}
var sm = Ext.create('Ext.selection.RowModel', {});
var store = Ext.create('Ext.data.Store', {
storeid: 'node-disk-list' + nodename,
model: 'node-disk-list',
proxy: {
type: 'pve',
url: "/api2/json/nodes/" + nodename + "/disks/list"
},
sorters: [
{
property : 'dev',
direction: 'ASC'
}
]
});
var reloadButton = Ext.create('PVE.button.Button', {
text: gettext('Reload'),
handler: function() {
me.store.load();
}
});
var smartButton = Ext.create('PVE.button.Button', {
text: gettext('Show S.M.A.R.T. values'),
selModel: sm,
enableFn: function() {
return !!sm.getSelection().length;
},
disabled: true,
handler: function() {
var rec = sm.getSelection()[0];
var win = Ext.create('PVE.DiskSmartWindow', {
nodename: nodename,
dev: rec.data.devpath
});
win.show();
}
});
var initButton = Ext.create('PVE.button.Button', {
text: gettext('Initialize Disk with GPT'),
selModel: sm,
enableFn: function() {
var selection = sm.getSelection();
if (!selection.length || selection[0].data.used) {
return false;
} else {
return true;
}
},
disabled: true,
handler: function() {
var rec = sm.getSelection()[0];
PVE.Utils.API2Request({
url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
waitMsgTarget: me,
method: 'POST',
params: { disk: rec.data.devpath},
failure: function(response, options) {
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
},
success: function(response, options) {
var upid = response.result.data;
var win = Ext.create('PVE.window.TaskProgress', {
upid: upid
});
win.show();
}
});
}
});
me.loadCount = 1; // avoid duplicate loadmask
PVE.Utils.monStoreErrors(me, store);
Ext.apply(me, {
emptyText: gettext('No Disk found'),
store: store,
selModel: sm,
stateful: false,
tbar: [ reloadButton, smartButton, initButton ],
listeners: {
itemdblclick: function() {
var rec = sm.getSelection()[0];
var win = Ext.create('PVE.DiskSmartWindow', {
nodename: nodename,
dev: rec.data.devpath
});
win.show();
}
}
});
me.callParent();
me.store.load();
}
}, function() {
Ext.define('node-disk-list', {
extend: 'Ext.data.Model',
fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
{name: 'osdid', type: 'number'},
'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
idProperty: 'devpath'
});
});
Ext.define('PVE.DiskSmartWindow', {
extend: 'Ext.window.Window',
alias: 'widget.pveSmartWindow',
modal: true,
items: [
{
xtype: 'gridpanel',
layout: {
type: 'fit'
},
emptyText: gettext('No S.M.A.R.T. Values'),
scrollable: true,
flex: 1,
itemId: 'smarts',
reserveScrollbar: true,
columns: [
{ text: 'ID', dataIndex: 'id', width: 50 },
{ text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
{ text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
{ text: gettext('Normalized'), dataIndex: 'value', width: 60},
{ text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
{ text: gettext('Worst'), dataIndex: 'worst', width: 60},
{ text: gettext('Flags'), dataIndex: 'flags'},
{ text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
]
},
{
xtype: 'component',
itemId: 'text',
layout: {
type: 'fit'
},
hidden: true,
style: {
'background-color': 'white',
'white-space': 'pre',
'font-family': 'monospace'
}
}
],
buttons: [
{
text: gettext('Reload'),
name: 'reload',
handler: function() {
var me = this;
me.up('window').store.reload();
}
},
{
text: gettext('Close'),
name: 'close',
handler: function() {
var me = this;
me.up('window').close();
}
}
],
layout: {
type: 'vbox',
align: 'stretch'
},
width: 800,
height: 500,
minWidth: 600,
minHeight: 400,
bodyPadding: 5,
title: gettext('S.M.A.R.T. Values'),
initComponent: function() {
var me = this;
var nodename = me.nodename;
if (!nodename) {
throw "no node name specified";
}
var dev = me.dev;
if (!dev) {
throw "no device specified";
}
me.store = Ext.create('Ext.data.Store', {
model: 'disk-smart',
proxy: {
type: 'pve',
url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
}
});
me.callParent();
var grid = me.down('#smarts');
var text = me.down('#text');
PVE.Utils.monStoreErrors(grid, me.store);
me.mon(me.store, 'load', function(s, records, success) {
if (success && records.length > 0) {
var rec = records[0];
switch (rec.data.type) {
case 'text':
grid.setVisible(false);
text.setVisible(true);
text.setHtml(Ext.String.htmlEncode(rec.data.text));
break;
default:
// includes 'ata'
// cannot use empty case because
// of jslint
grid.setVisible(true);
text.setVisible(false);
grid.setStore(rec.attributes());
break;
}
}
});
me.store.load();
}
}, function() {
Ext.define('disk-smart', {
extend: 'Ext.data.Model',
fields: [
{ name:'health'},
{ name:'type'},
{ name:'text'}
],
hasMany: {model: 'smart-attribute', name: 'attributes'}
});
Ext.define('smart-attribute', {
extend: 'Ext.data.Model',
fields: [
{ name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
],
belongsTo: 'disk-smart'
});
});