5e9cce24a2
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
387 lines
8.2 KiB
JavaScript
387 lines
8.2 KiB
JavaScript
Ext.define('PVE.lxc.MountPointInputPanel', {
|
|
extend: 'Proxmox.panel.InputPanel',
|
|
xtype: 'pveLxcMountPointInputPanel',
|
|
|
|
onlineHelp: 'pct_container_storage',
|
|
|
|
insideWizard: false,
|
|
|
|
unused: false, // add unused disk imaged
|
|
unprivileged: false,
|
|
|
|
vmconfig: {}, // used to select unused disks
|
|
|
|
setUnprivileged: function(unprivileged) {
|
|
var me = this;
|
|
var vm = me.getViewModel();
|
|
me.unprivileged = unprivileged;
|
|
vm.set('unpriv', unprivileged);
|
|
},
|
|
|
|
onGetValues: function(values) {
|
|
var me = this;
|
|
|
|
var confid = me.confid || "mp"+values.mpid;
|
|
me.mp.file = me.down('field[name=file]').getValue();
|
|
|
|
if (me.unused) {
|
|
confid = "mp"+values.mpid;
|
|
} else if (me.isCreate) {
|
|
me.mp.file = values.hdstorage + ':' + values.disksize;
|
|
}
|
|
|
|
// delete unnecessary fields
|
|
delete values.mpid;
|
|
delete values.hdstorage;
|
|
delete values.disksize;
|
|
delete values.diskformat;
|
|
|
|
let setMPOpt = (k, src, v) => PVE.Utils.propertyStringSet(me.mp, src, k, v);
|
|
|
|
setMPOpt('mp', values.mp);
|
|
let mountOpts = (values.mountoptions || []).join(';');
|
|
setMPOpt('mountoptions', values.mountoptions, mountOpts);
|
|
setMPOpt('mp', values.mp);
|
|
setMPOpt('backup', values.backup);
|
|
setMPOpt('quota', values.quota);
|
|
setMPOpt('ro', values.ro);
|
|
setMPOpt('acl', values.acl);
|
|
setMPOpt('replicate', values.replicate);
|
|
|
|
let res = {};
|
|
res[confid] = PVE.Parser.printLxcMountPoint(me.mp);
|
|
return res;
|
|
},
|
|
|
|
setMountPoint: function(mp) {
|
|
let me = this;
|
|
let vm = me.getViewModel();
|
|
vm.set('mptype', mp.type);
|
|
if (mp.mountoptions) {
|
|
mp.mountoptions = mp.mountoptions.split(';');
|
|
}
|
|
me.mp = mp;
|
|
me.filterMountOptions();
|
|
me.setValues(mp);
|
|
},
|
|
|
|
filterMountOptions: function() {
|
|
let me = this;
|
|
if (me.confid === 'rootfs') {
|
|
let field = me.down('field[name=mountoptions]');
|
|
let exclude = ['nodev', 'noexec'];
|
|
let filtered = field.comboItems.filter(v => !exclude.includes(v[0]));
|
|
field.setComboItems(filtered);
|
|
}
|
|
},
|
|
|
|
setVMConfig: function(vmconfig) {
|
|
let me = this;
|
|
let vm = me.getViewModel();
|
|
me.vmconfig = vmconfig;
|
|
vm.set('unpriv', vmconfig.unprivileged);
|
|
|
|
PVE.Utils.forEachMP((bus, i) => {
|
|
let name = "mp" + i.toString();
|
|
if (!Ext.isDefined(vmconfig[name])) {
|
|
me.down('field[name=mpid]').setValue(i);
|
|
return false;
|
|
}
|
|
return undefined;
|
|
});
|
|
},
|
|
|
|
setNodename: function(nodename) {
|
|
let me = this;
|
|
let vm = me.getViewModel();
|
|
vm.set('node', nodename);
|
|
me.down('#diskstorage').setNodename(nodename);
|
|
},
|
|
|
|
controller: {
|
|
xclass: 'Ext.app.ViewController',
|
|
|
|
control: {
|
|
'field[name=mpid]': {
|
|
change: function(field, value) {
|
|
field.validate();
|
|
},
|
|
},
|
|
'#hdstorage': {
|
|
change: function(field, newValue) {
|
|
let me = this;
|
|
if (!newValue) {
|
|
return;
|
|
}
|
|
|
|
let rec = field.store.getById(newValue);
|
|
if (!rec) {
|
|
return;
|
|
}
|
|
me.getViewModel().set('type', rec.data.type);
|
|
},
|
|
},
|
|
},
|
|
init: function(view) {
|
|
let me = this;
|
|
let vm = this.getViewModel();
|
|
view.mp = {};
|
|
vm.set('confid', view.confid);
|
|
vm.set('unused', view.unused);
|
|
vm.set('node', view.nodename);
|
|
vm.set('unpriv', view.unprivileged);
|
|
vm.set('hideStorSelector', view.unused || !view.isCreate);
|
|
|
|
if (view.isCreate) { // can be array if created from unused disk
|
|
vm.set('isIncludedInBackup', true);
|
|
if (view.insideWizard) {
|
|
view.filterMountOptions();
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
viewModel: {
|
|
data: {
|
|
unpriv: false,
|
|
unused: false,
|
|
showStorageSelector: false,
|
|
mptype: '',
|
|
type: '',
|
|
confid: '',
|
|
node: '',
|
|
},
|
|
|
|
formulas: {
|
|
quota: function(get) {
|
|
return !(get('type') === 'zfs' ||
|
|
get('type') === 'zfspool' ||
|
|
get('unpriv') ||
|
|
get('isBind'));
|
|
},
|
|
hasMP: function(get) {
|
|
return !!get('confid') && !get('unused');
|
|
},
|
|
isRoot: function(get) {
|
|
return get('confid') === 'rootfs';
|
|
},
|
|
isBind: function(get) {
|
|
return get('mptype') === 'bind';
|
|
},
|
|
isBindOrRoot: function(get) {
|
|
return get('isBind') || get('isRoot');
|
|
},
|
|
},
|
|
},
|
|
|
|
column1: [
|
|
{
|
|
xtype: 'proxmoxintegerfield',
|
|
name: 'mpid',
|
|
fieldLabel: gettext('Mount Point ID'),
|
|
minValue: 0,
|
|
maxValue: PVE.Utils.mp_counts.mps - 1,
|
|
hidden: true,
|
|
allowBlank: false,
|
|
disabled: true,
|
|
bind: {
|
|
hidden: '{hasMP}',
|
|
disabled: '{hasMP}',
|
|
},
|
|
validator: function(value) {
|
|
let view = this.up('inputpanel');
|
|
if (!view.rendered) {
|
|
return undefined;
|
|
}
|
|
if (Ext.isDefined(view.vmconfig["mp"+value])) {
|
|
return "Mount point is already in use.";
|
|
}
|
|
return true;
|
|
},
|
|
},
|
|
{
|
|
xtype: 'pveDiskStorageSelector',
|
|
itemId: 'diskstorage',
|
|
storageContent: 'rootdir',
|
|
hidden: true,
|
|
autoSelect: true,
|
|
selectformat: false,
|
|
defaultSize: 8,
|
|
bind: {
|
|
hidden: '{hideStorSelector}',
|
|
disabled: '{hideStorSelector}',
|
|
nodename: '{node}',
|
|
},
|
|
},
|
|
{
|
|
xtype: 'textfield',
|
|
disabled: true,
|
|
submitValue: false,
|
|
fieldLabel: gettext('Disk image'),
|
|
name: 'file',
|
|
bind: {
|
|
hidden: '{!hideStorSelector}',
|
|
},
|
|
},
|
|
],
|
|
|
|
column2: [
|
|
{
|
|
xtype: 'textfield',
|
|
name: 'mp',
|
|
value: '',
|
|
emptyText: gettext('/some/path'),
|
|
allowBlank: false,
|
|
disabled: true,
|
|
fieldLabel: gettext('Path'),
|
|
bind: {
|
|
hidden: '{isRoot}',
|
|
disabled: '{isRoot}',
|
|
},
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
name: 'backup',
|
|
fieldLabel: gettext('Backup'),
|
|
autoEl: {
|
|
tag: 'div',
|
|
'data-qtip': gettext('Include volume in backup job'),
|
|
},
|
|
bind: {
|
|
hidden: '{isRoot}',
|
|
disabled: '{isBindOrRoot}',
|
|
value: '{isIncludedInBackup}',
|
|
},
|
|
},
|
|
],
|
|
|
|
advancedColumn1: [
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
name: 'quota',
|
|
defaultValue: 0,
|
|
bind: {
|
|
disabled: '{!quota}',
|
|
},
|
|
fieldLabel: gettext('Enable quota'),
|
|
listeners: {
|
|
disable: function() {
|
|
this.reset();
|
|
},
|
|
},
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
name: 'ro',
|
|
defaultValue: 0,
|
|
bind: {
|
|
hidden: '{isRoot}',
|
|
disabled: '{isRoot}',
|
|
},
|
|
fieldLabel: gettext('Read-only'),
|
|
},
|
|
{
|
|
xtype: 'proxmoxKVComboBox',
|
|
name: 'mountoptions',
|
|
fieldLabel: gettext('Mount options'),
|
|
deleteEmpty: false,
|
|
comboItems: [
|
|
['noatime', 'noatime'],
|
|
['nodev', 'nodev'],
|
|
['noexec', 'noexec'],
|
|
['nosuid', 'nosuid'],
|
|
],
|
|
multiSelect: true,
|
|
value: [],
|
|
allowBlank: true,
|
|
},
|
|
],
|
|
|
|
advancedColumn2: [
|
|
{
|
|
xtype: 'proxmoxKVComboBox',
|
|
name: 'acl',
|
|
fieldLabel: 'ACLs',
|
|
deleteEmpty: false,
|
|
comboItems: [
|
|
['__default__', Proxmox.Utils.defaultText],
|
|
['1', Proxmox.Utils.enabledText],
|
|
['0', Proxmox.Utils.disabledText],
|
|
],
|
|
value: '__default__',
|
|
bind: {
|
|
disabled: '{isBind}',
|
|
},
|
|
allowBlank: true,
|
|
},
|
|
{
|
|
xtype: 'proxmoxcheckbox',
|
|
inputValue: '0', // reverses the logic
|
|
name: 'replicate',
|
|
fieldLabel: gettext('Skip replication'),
|
|
},
|
|
],
|
|
});
|
|
|
|
Ext.define('PVE.lxc.MountPointEdit', {
|
|
extend: 'Proxmox.window.Edit',
|
|
|
|
unprivileged: false,
|
|
|
|
initComponent: function() {
|
|
let me = this;
|
|
|
|
let nodename = me.pveSelNode.data.node;
|
|
if (!nodename) {
|
|
throw "no node name specified";
|
|
}
|
|
|
|
let unused = me.confid && me.confid.match(/^unused\d+$/);
|
|
|
|
me.isCreate = me.confid ? unused : true;
|
|
|
|
let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
|
|
confid: me.confid,
|
|
nodename: nodename,
|
|
unused: unused,
|
|
unprivileged: me.unprivileged,
|
|
isCreate: me.isCreate,
|
|
});
|
|
|
|
let subject;
|
|
if (unused) {
|
|
subject = gettext('Unused Disk');
|
|
} else if (me.isCreate) {
|
|
subject = gettext('Mount Point');
|
|
} else {
|
|
subject = gettext('Mount Point') + ' (' + me.confid + ')';
|
|
}
|
|
|
|
Ext.apply(me, {
|
|
subject: subject,
|
|
defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
|
|
items: ipanel,
|
|
});
|
|
|
|
me.callParent();
|
|
|
|
me.load({
|
|
success: function(response, options) {
|
|
ipanel.setVMConfig(response.result.data);
|
|
|
|
if (me.confid) {
|
|
let value = response.result.data[me.confid];
|
|
let mp = PVE.Parser.parseLxcMountPoint(value);
|
|
if (!mp) {
|
|
Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
|
|
me.close();
|
|
return;
|
|
}
|
|
ipanel.setMountPoint(mp);
|
|
me.isValid(); // trigger validation
|
|
}
|
|
},
|
|
});
|
|
},
|
|
});
|