mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-05 14:32:46 +00:00
add firewall GUI classes
This commit is contained in:
parent
98282daade
commit
434f2466b4
230
www/manager/dc/SecurityGroups.js
Normal file
230
www/manager/dc/SecurityGroups.js
Normal file
@ -0,0 +1,230 @@
|
||||
Ext.define('PVE.SecurityGroupEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
base_url: "/cluster/firewall/groups",
|
||||
|
||||
allow_iface: false,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
me.create = (me.group_name === undefined);
|
||||
|
||||
var subject;
|
||||
|
||||
me.url = '/api2/extjs' + me.base_url;
|
||||
me.method = 'POST';
|
||||
|
||||
var items = [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'group',
|
||||
value: me.group_name || '',
|
||||
fieldLabel: gettext('Name'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: me.group_comment || '',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
];
|
||||
|
||||
if (me.create) {
|
||||
subject = gettext('Security Group');
|
||||
} else {
|
||||
subject = gettext('Security Group') + " '" + me.group_name + "'";
|
||||
items.push({
|
||||
xtype: 'hiddenfield',
|
||||
name: 'rename',
|
||||
value: me.group_name
|
||||
});
|
||||
}
|
||||
|
||||
var ipanel = Ext.create('PVE.panel.InputPanel', {
|
||||
create: me.create,
|
||||
items: items
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: subject,
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.SecurityGroupList', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: 'widget.pveSecurityGroupList',
|
||||
|
||||
rule_panel: undefined,
|
||||
|
||||
addBtn: undefined,
|
||||
removeBtn: undefined,
|
||||
editBtn: undefined,
|
||||
|
||||
base_url: "/cluster/firewall/groups",
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (me.rule_panel == undefined) {
|
||||
throw "no rule panel specified";
|
||||
}
|
||||
|
||||
if (me.base_url == undefined) {
|
||||
throw "no base_url specified";
|
||||
}
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
fields: [ 'group', 'comment', 'digest' ],
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: '/api2/json' + me.base_url
|
||||
},
|
||||
idProperty: 'group',
|
||||
sorters: {
|
||||
property: 'group',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var reload = function() {
|
||||
var oldrec = sm.getSelection()[0];
|
||||
store.load(function(records, operation, success) {
|
||||
if (oldrec) {
|
||||
var rec = store.findRecord('group', oldrec.data.group);
|
||||
if (rec) {
|
||||
sm.select(rec);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
var win = Ext.create('PVE.SecurityGroupEdit', {
|
||||
digest: rec.data.digest,
|
||||
group_name: rec.data.group,
|
||||
group_comment: rec.data.comment
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
me.editBtn = new PVE.button.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
selModel: sm,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
me.addBtn = new PVE.button.Button({
|
||||
text: gettext('Create'),
|
||||
handler: function() {
|
||||
sm.deselectAll();
|
||||
var win = Ext.create('PVE.SecurityGroupEdit', {});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
}
|
||||
});
|
||||
|
||||
me.removeBtn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec || !me.base_url) {
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + rec.data.group +
|
||||
'?digest=' + encodeURIComponent(rec.data.digest),
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: reload
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
|
||||
selModel: sm,
|
||||
columns: [
|
||||
{ header: gettext('Group'), dataIndex: 'group', width: 100 },
|
||||
{ header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor,
|
||||
select: function(sm, rec) {
|
||||
var url = '/cluster/firewall/groups/' + rec.data.group;
|
||||
me.rule_panel.setBaseUrl(url);
|
||||
},
|
||||
deselect: function() {
|
||||
me.rule_panel.setBaseUrl(undefined);
|
||||
},
|
||||
show: reload
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.load();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.SecurityGroups', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pveSecurityGroups',
|
||||
|
||||
title: 'Security Groups',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var rule_panel = Ext.createWidget('pveFirewallRules', {
|
||||
region: 'center',
|
||||
allow_groups: false,
|
||||
tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
|
||||
flex: 0.75,
|
||||
border: false
|
||||
});
|
||||
|
||||
var sglist = Ext.createWidget('pveSecurityGroupList', {
|
||||
region: 'west',
|
||||
rule_panel: rule_panel,
|
||||
flex: 0.25,
|
||||
border: false,
|
||||
split: true
|
||||
});
|
||||
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: 'border',
|
||||
items: [ sglist, rule_panel ],
|
||||
listeners: {
|
||||
show: function() {
|
||||
sglist.fireEvent('show', sglist);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
185
www/manager/grid/FirewallAliases.js
Normal file
185
www/manager/grid/FirewallAliases.js
Normal file
@ -0,0 +1,185 @@
|
||||
Ext.define('PVE.FirewallAliasEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
alias_name: undefined,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
me.create = (me.alias_name === undefined);
|
||||
|
||||
if (me.create) {
|
||||
me.url = '/api2/extjs' + me.base_url;
|
||||
me.method = 'POST';
|
||||
} else {
|
||||
me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
|
||||
me.method = 'PUT';
|
||||
}
|
||||
|
||||
var items = [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: me.create ? 'name' : 'rename',
|
||||
fieldLabel: gettext('Name'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'cidr',
|
||||
fieldLabel: gettext('IP/CIDR'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
];
|
||||
|
||||
var ipanel = Ext.create('PVE.panel.InputPanel', {
|
||||
create: me.create,
|
||||
items: items
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: gettext('Alias'),
|
||||
isAdd: true,
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!me.create) {
|
||||
me.load({
|
||||
success: function(response, options) {
|
||||
var values = response.result.data;
|
||||
values.rename = values.name;
|
||||
ipanel.setValues(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.FirewallAliases', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: ['widget.pveFirewallAliases'],
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
title: gettext('Aliases'),
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
throw "missing base_url configuration";
|
||||
}
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
fields: [ 'name', 'cidr', 'comment', 'digest' ],
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json" + me.base_url
|
||||
},
|
||||
idProperty: 'name',
|
||||
sorters: {
|
||||
property: 'name',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var reload = function() {
|
||||
var oldrec = sm.getSelection()[0];
|
||||
store.load(function(records, operation, success) {
|
||||
if (oldrec) {
|
||||
var rec = store.findRecord('name', oldrec.data.name);
|
||||
if (rec) {
|
||||
sm.select(rec);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
|
||||
var win = Ext.create('PVE.FirewallAliasEdit', {
|
||||
base_url: me.base_url,
|
||||
alias_name: rec.data.name
|
||||
});
|
||||
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
me.editBtn = new PVE.button.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
selModel: sm,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
me.addBtn = Ext.create('Ext.Button', {
|
||||
text: gettext('Add'),
|
||||
handler: function() {
|
||||
var win = Ext.create('PVE.FirewallAliasEdit', {
|
||||
base_url: me.base_url
|
||||
});
|
||||
win.on('destroy', reload);
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
me.removeBtn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + rec.data.name,
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: reload
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Ext.applyIf(me, {
|
||||
store: store,
|
||||
tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
|
||||
selModel: sm,
|
||||
columns: [
|
||||
{ header: gettext('Name'), dataIndex: 'name', width: 100 },
|
||||
{ header: gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
|
||||
{ header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', reload);
|
||||
}
|
||||
});
|
227
www/manager/grid/FirewallOptions.js
Normal file
227
www/manager/grid/FirewallOptions.js
Normal file
@ -0,0 +1,227 @@
|
||||
Ext.define('PVE.FirewallOptions', {
|
||||
extend: 'PVE.grid.ObjectGrid',
|
||||
alias: ['widget.pveFirewallOptions'],
|
||||
|
||||
fwtype: undefined, // 'dc', 'node' or 'vm'
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
throw "missing base_url configuration";
|
||||
}
|
||||
|
||||
if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
|
||||
if (me.fwtype === 'node') {
|
||||
me.cwidth1 = 250;
|
||||
}
|
||||
} else {
|
||||
throw "unknown firewall option type";
|
||||
}
|
||||
|
||||
var rows = {};
|
||||
|
||||
var add_boolean_row = function(name, text, labelWidth) {
|
||||
rows[name] = {
|
||||
header: text,
|
||||
required: true,
|
||||
defaultValue: 0,
|
||||
renderer: PVE.Utils.format_boolean,
|
||||
editor: {
|
||||
xtype: 'pveWindowEdit',
|
||||
subject: text,
|
||||
fieldDefaults: { labelWidth: labelWidth || 100 },
|
||||
items: {
|
||||
xtype: 'pvecheckbox',
|
||||
name: name,
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: text
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var add_integer_row = function(name, text, labelWidth, minValue) {
|
||||
rows[name] = {
|
||||
header: text,
|
||||
required: true,
|
||||
renderer: function(value) {
|
||||
return value || PVE.Utils.defaultText;
|
||||
},
|
||||
editor: {
|
||||
xtype: 'pveWindowEdit',
|
||||
subject: text,
|
||||
fieldDefaults: { labelWidth: labelWidth || 100 },
|
||||
items: {
|
||||
xtype: 'numberfield',
|
||||
name: name,
|
||||
minValue: minValue,
|
||||
decimalPrecision: 0,
|
||||
fieldLabel: text,
|
||||
emptyText: gettext('Default'),
|
||||
getSubmitData: function() {
|
||||
var me = this;
|
||||
var val = me.getSubmitValue();
|
||||
if (val !== null && val !== '') {
|
||||
var data = {};
|
||||
data[name] = val;
|
||||
return data;
|
||||
} else {
|
||||
return { 'delete' : name };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var add_log_row = function(name, labelWidth) {
|
||||
rows[name] = {
|
||||
header: name,
|
||||
required: true,
|
||||
defaultValue: 'nolog',
|
||||
editor: {
|
||||
xtype: 'pveWindowEdit',
|
||||
subject: name,
|
||||
fieldDefaults: { labelWidth: labelWidth || 100 },
|
||||
items: {
|
||||
xtype: 'pveKVComboBox',
|
||||
name: name,
|
||||
fieldLabel: name,
|
||||
data: [['nolog', 'nolog'], ['info', 'info'], ['err', 'err'],
|
||||
['warning', 'warning'], ['crit', 'crit'], ['alert', 'alert'],
|
||||
['emerg', 'emerg'], ['debug', 'debug']]
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
add_boolean_row('enable', gettext('Enable Firewall'));
|
||||
|
||||
if (me.fwtype === 'node') {
|
||||
add_boolean_row('nosmurfs', gettext('SMURFS filter'));
|
||||
add_boolean_row('tcpflags', gettext('TCP flags filter'));
|
||||
add_boolean_row('allow_bridge_route', gettext('Allow bridge route'), 150);
|
||||
add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 120, 32768);
|
||||
add_integer_row('nf_conntrack_tcp_timeout_established',
|
||||
'nf_conntrack_tcp_timeout_established', 250, 7875);
|
||||
add_log_row('log_level_in');
|
||||
add_log_row('log_level_out');
|
||||
add_log_row('tcp_flags_log_level', 120);
|
||||
add_log_row('smurf_log_level');
|
||||
} else if (me.fwtype === 'vm') {
|
||||
add_boolean_row('dhcp', gettext('Enable DHCP'));
|
||||
add_boolean_row('macfilter', gettext('MAC filter'));
|
||||
add_log_row('log_level_in');
|
||||
add_log_row('log_level_out');
|
||||
}
|
||||
|
||||
if (me.fwtype === 'dc' || me.fwtype === 'vm') {
|
||||
rows.policy_in = {
|
||||
header: gettext('Input Policy'),
|
||||
required: true,
|
||||
defaultValue: 'DROP',
|
||||
editor: {
|
||||
xtype: 'pveWindowEdit',
|
||||
subject: gettext('Input Policy'),
|
||||
items: {
|
||||
xtype: 'pveFirewallPolicySelector',
|
||||
name: 'policy_in',
|
||||
value: 'DROP',
|
||||
fieldLabel: gettext('Input Policy')
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rows.policy_out = {
|
||||
header: gettext('Output Policy'),
|
||||
required: true,
|
||||
defaultValue: 'ACCEPT',
|
||||
editor: {
|
||||
xtype: 'pveWindowEdit',
|
||||
subject: gettext('Output Policy'),
|
||||
items: {
|
||||
xtype: 'pveFirewallPolicySelector',
|
||||
name: 'policy_out',
|
||||
value: 'ACCEPT',
|
||||
fieldLabel: gettext('Output Policy')
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var reload = function() {
|
||||
me.rstore.load();
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowdef = rows[rec.data.key];
|
||||
if (!rowdef.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
var win;
|
||||
if (Ext.isString(rowdef.editor)) {
|
||||
win = Ext.create(rowdef.editor, {
|
||||
pveSelNode: me.pveSelNode,
|
||||
confid: rec.data.key,
|
||||
url: '/api2/extjs' + me.base_url
|
||||
});
|
||||
} else {
|
||||
var config = Ext.apply({
|
||||
pveSelNode: me.pveSelNode,
|
||||
confid: rec.data.key,
|
||||
url: '/api2/extjs' + me.base_url
|
||||
}, rowdef.editor);
|
||||
win = Ext.createWidget(rowdef.editor.xtype, config);
|
||||
win.load();
|
||||
}
|
||||
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
var edit_btn = new Ext.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
var set_button_status = function() {
|
||||
var sm = me.getSelectionModel();
|
||||
var rec = sm.getSelection()[0];
|
||||
|
||||
if (!rec) {
|
||||
edit_btn.disable();
|
||||
return;
|
||||
}
|
||||
var rowdef = rows[rec.data.key];
|
||||
edit_btn.setDisabled(!rowdef.editor);
|
||||
};
|
||||
|
||||
Ext.applyIf(me, {
|
||||
url: "/api2/json" + me.base_url,
|
||||
cwidth1: 150,
|
||||
tbar: [ edit_btn ],
|
||||
rows: rows,
|
||||
listeners: {
|
||||
itemdblclick: run_editor,
|
||||
selectionchange: set_button_status
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on('show', reload);
|
||||
}
|
||||
});
|
699
www/manager/grid/FirewallRules.js
Normal file
699
www/manager/grid/FirewallRules.js
Normal file
@ -0,0 +1,699 @@
|
||||
Ext.define('PVE.form.FWMacroSelector', {
|
||||
extend: 'PVE.form.ComboGrid',
|
||||
alias: 'widget.pveFWMacroSelector',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var store = Ext.create('Ext.data.Store', {
|
||||
autoLoad: true,
|
||||
fields: [ 'macro', 'descr' ],
|
||||
idProperty: 'macro',
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json/cluster/firewall/macros"
|
||||
},
|
||||
sorters: {
|
||||
property: 'macro',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
allowBlank: true,
|
||||
autoSelect: false,
|
||||
valueField: 'macro',
|
||||
displayField: 'macro',
|
||||
listConfig: {
|
||||
columns: [
|
||||
{
|
||||
header: gettext('Macro'),
|
||||
dataIndex: 'macro',
|
||||
hideable: false,
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Description'),
|
||||
flex: 1,
|
||||
dataIndex: 'descr'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.FirewallRulePanel', {
|
||||
extend: 'PVE.panel.InputPanel',
|
||||
|
||||
allow_iface: false,
|
||||
|
||||
initComponent : function() {
|
||||
var me = this;
|
||||
|
||||
me.column1 = [
|
||||
{
|
||||
xtype: 'pveKVComboBox',
|
||||
name: 'type',
|
||||
value: 'in',
|
||||
data: [['in', 'in'], ['out', 'out']],
|
||||
fieldLabel: gettext('Direction'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'pveKVComboBox',
|
||||
name: 'action',
|
||||
value: 'ACCEPT',
|
||||
data: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
|
||||
fieldLabel: gettext('Action'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'pveKVComboBox',
|
||||
name: 'proto',
|
||||
value: '',
|
||||
deleteEmpty: !me.create,
|
||||
emptyText: 'any',
|
||||
editable: true,
|
||||
data: [['tcp', 'TCP'], ['udp', 'UDP'], ['icmp', 'ICMP']],
|
||||
fieldLabel: gettext('Protocol'),
|
||||
allowBlank: true
|
||||
},
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
fieldLabel: '',
|
||||
height: 7,
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
xtype: 'pveIPSetSelector',
|
||||
name: 'source',
|
||||
autoSelect: false,
|
||||
editable: true,
|
||||
queryDelay: 900000000, // disable query
|
||||
value: '',
|
||||
fieldLabel: gettext('Source')
|
||||
},
|
||||
{
|
||||
xtype: 'pveIPSetSelector',
|
||||
name: 'dest',
|
||||
autoSelect: false,
|
||||
queryDelay: 900000000, // disable query
|
||||
editable: true,
|
||||
value: '',
|
||||
fieldLabel: gettext('Destination')
|
||||
}
|
||||
];
|
||||
|
||||
me.column2 = [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'enable',
|
||||
checked: false,
|
||||
height: 22, // hack: set same height as text fields
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: gettext('Enable')
|
||||
},
|
||||
{
|
||||
xtype: 'pveFWMacroSelector',
|
||||
name: 'macro',
|
||||
value: '',
|
||||
deleteEmpty: !me.create,
|
||||
fieldLabel: gettext('Macro'),
|
||||
allowBlank: true
|
||||
}
|
||||
];
|
||||
|
||||
if (me.allow_iface) {
|
||||
me.column2.push({
|
||||
xtype: 'pvetextfield',
|
||||
name: 'iface',
|
||||
deleteEmpty: !me.create,
|
||||
value: '',
|
||||
fieldLabel: gettext('Interface')
|
||||
});
|
||||
} else {
|
||||
me.column2.push({
|
||||
xtype: 'displayfield',
|
||||
fieldLabel: '',
|
||||
height: 22, // hack: set same height as text fields
|
||||
value: ''
|
||||
});
|
||||
}
|
||||
|
||||
me.column2.push([
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
fieldLabel: '',
|
||||
height: 7,
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'sport',
|
||||
value: '',
|
||||
fieldLabel: gettext('Source port')
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'dport',
|
||||
height: 22, // hack: set same height as text fields
|
||||
value: '',
|
||||
fieldLabel: gettext('Dest. port')
|
||||
}
|
||||
]);
|
||||
|
||||
me.columnB = [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: '',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
];
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.FirewallRuleEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
allow_iface: false,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
me.create = (me.rule_pos === undefined);
|
||||
|
||||
if (me.create) {
|
||||
me.url = '/api2/extjs' + me.base_url;
|
||||
me.method = 'POST';
|
||||
} else {
|
||||
me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
|
||||
me.method = 'PUT';
|
||||
}
|
||||
|
||||
var ipanel = Ext.create('PVE.FirewallRulePanel', {
|
||||
create: me.create,
|
||||
allow_iface: me.allow_iface,
|
||||
rule_pos: me.rule_pos
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: gettext('Rule'),
|
||||
isAdd: true,
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!me.create) {
|
||||
me.load({
|
||||
success: function(response, options) {
|
||||
var values = response.result.data;
|
||||
ipanel.setValues(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.FirewallGroupRuleEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
allow_iface: false,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
me.create = (me.rule_pos === undefined);
|
||||
|
||||
if (me.create) {
|
||||
me.url = '/api2/extjs' + me.base_url;
|
||||
me.method = 'POST';
|
||||
} else {
|
||||
me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
|
||||
me.method = 'PUT';
|
||||
}
|
||||
|
||||
var column1 = [
|
||||
{
|
||||
xtype: 'hiddenfield',
|
||||
name: 'type',
|
||||
value: 'group'
|
||||
},
|
||||
{
|
||||
xtype: 'pveSecurityGroupsSelector',
|
||||
name: 'action',
|
||||
value: '',
|
||||
fieldLabel: gettext('Security Group'),
|
||||
allowBlank: false
|
||||
}
|
||||
];
|
||||
|
||||
if (me.allow_iface) {
|
||||
column1.push({
|
||||
xtype: 'pvetextfield',
|
||||
name: 'iface',
|
||||
deleteEmpty: !me.create,
|
||||
value: '',
|
||||
fieldLabel: gettext('Interface')
|
||||
});
|
||||
}
|
||||
|
||||
var ipanel = Ext.create('PVE.panel.InputPanel', {
|
||||
create: me.create,
|
||||
column1: column1,
|
||||
column2: [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'enable',
|
||||
checked: false,
|
||||
height: 22, // hack: set same height as text fields
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: gettext('Enable')
|
||||
}
|
||||
],
|
||||
columnB: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: '',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: gettext('Rule'),
|
||||
isAdd: true,
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!me.create) {
|
||||
me.load({
|
||||
success: function(response, options) {
|
||||
var values = response.result.data;
|
||||
ipanel.setValues(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.FirewallRules', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: 'widget.pveFirewallRules',
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
addBtn: undefined,
|
||||
removeBtn: undefined,
|
||||
editBtn: undefined,
|
||||
groupBtn: undefined,
|
||||
|
||||
tbar_prefix: undefined,
|
||||
|
||||
allow_groups: true,
|
||||
allow_iface: false,
|
||||
|
||||
setBaseUrl: function(url) {
|
||||
var me = this;
|
||||
|
||||
me.base_url = url;
|
||||
|
||||
if (url === undefined) {
|
||||
me.addBtn.setDisabled(true);
|
||||
if (me.groupBtn) {
|
||||
me.groupBtn.setDisabled(true);
|
||||
}
|
||||
me.store.removeAll();
|
||||
} else {
|
||||
me.addBtn.setDisabled(false);
|
||||
if (me.groupBtn) {
|
||||
me.groupBtn.setDisabled(false);
|
||||
}
|
||||
me.store.setProxy({
|
||||
type: 'pve',
|
||||
url: '/api2/json' + url
|
||||
});
|
||||
|
||||
me.store.load();
|
||||
}
|
||||
},
|
||||
|
||||
moveRule: function(from, to) {
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + "/" + from,
|
||||
method: 'PUT',
|
||||
params: { moveto: to },
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: function() {
|
||||
me.store.load();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createRule: function(editor, rule) {
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
rule.pos = 0;
|
||||
|
||||
rule.enable = rule.enable ? 1 : 0;
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url,
|
||||
method: 'POST',
|
||||
params: rule,
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
if (editor) {
|
||||
editor.form.markInvalid(response.result.errors);
|
||||
} else {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
},
|
||||
callback: function() {
|
||||
me.store.load();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateRule: function(editor, rule) {
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
rule.enable = rule.enable ? 1 : 0;
|
||||
|
||||
var pos = rule.pos;
|
||||
delete rule.pos;
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + pos.toString(),
|
||||
method: 'PUT',
|
||||
params: rule,
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
if (editor) {
|
||||
editor.form.markInvalid(response.result.errors);
|
||||
} else {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
}
|
||||
},
|
||||
callback: function() {
|
||||
me.store.load();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deleteRule: function(rule) {
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + rule.pos.toString() +
|
||||
'?digest=' + encodeURIComponent(rule.digest),
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: function() {
|
||||
me.store.load();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
model: 'pve-fw-rule'
|
||||
});
|
||||
|
||||
var reload = function() {
|
||||
store.load();
|
||||
};
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var run_editor = function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
var type = rec.data.type;
|
||||
|
||||
var editor;
|
||||
if (type === 'in' || type === 'out') {
|
||||
editor = 'PVE.FirewallRuleEdit';
|
||||
} else if (type === 'group') {
|
||||
editor = 'PVE.FirewallGroupRuleEdit';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var win = Ext.create(editor, {
|
||||
digest: rec.data.digest,
|
||||
allow_iface: me.allow_iface,
|
||||
base_url: me.base_url,
|
||||
rule_pos: rec.data.pos
|
||||
});
|
||||
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
me.editBtn = new PVE.button.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
selModel: sm,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
me.addBtn = Ext.create('Ext.Button', {
|
||||
text: gettext('Add'),
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var win = Ext.create('PVE.FirewallRuleEdit', {
|
||||
allow_iface: me.allow_iface,
|
||||
base_url: me.base_url
|
||||
});
|
||||
win.on('destroy', reload);
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
if (me.allow_groups) {
|
||||
me.groupBtn = Ext.create('Ext.Button', {
|
||||
text: gettext('Insert') + ': ' + gettext('Security Group'),
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var win = Ext.create('PVE.FirewallGroupRuleEdit', {
|
||||
allow_iface: me.allow_iface,
|
||||
base_url: me.base_url
|
||||
});
|
||||
win.on('destroy', reload);
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
me.removeBtn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
me.deleteRule(rec.data);
|
||||
}
|
||||
});
|
||||
|
||||
var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
|
||||
tbar.push(me.addBtn);
|
||||
if (me.groupBtn) {
|
||||
tbar.push(me.groupBtn);
|
||||
}
|
||||
tbar.push([ me.removeBtn, me.editBtn ]);
|
||||
|
||||
var columns = [
|
||||
{
|
||||
// similar to xtype: 'rownumberer',
|
||||
dataIndex: 'pos',
|
||||
resizable: false,
|
||||
width: 23,
|
||||
sortable: false,
|
||||
align: 'right',
|
||||
hideable: false,
|
||||
menuDisabled: true,
|
||||
renderer: function(value, metaData, record, rowIdx, colIdx, store) {
|
||||
metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
|
||||
if (value >= 0) {
|
||||
return value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
xtype: 'checkcolumn',
|
||||
header: gettext('Enable'),
|
||||
dataIndex: 'enable',
|
||||
listeners: {
|
||||
checkchange: function(column, record, checked) {
|
||||
record.commit();
|
||||
var data = {};
|
||||
record.fields.each(function(field) {
|
||||
data[field.name] = record.get(field.name);
|
||||
});
|
||||
if (!me.allow_iface || !data.iface) {
|
||||
delete data.iface;
|
||||
}
|
||||
me.updateRule(undefined, data);
|
||||
}
|
||||
},
|
||||
width: 50
|
||||
},
|
||||
{
|
||||
header: gettext('Type'),
|
||||
dataIndex: 'type',
|
||||
width: 50
|
||||
},
|
||||
{
|
||||
header: gettext('Action'),
|
||||
dataIndex: 'action',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
header: gettext('Macro'),
|
||||
dataIndex: 'macro',
|
||||
width: 80
|
||||
}
|
||||
];
|
||||
|
||||
if (me.allow_iface) {
|
||||
columns.push({
|
||||
header: gettext('Interface'),
|
||||
dataIndex: 'iface',
|
||||
width: 80
|
||||
});
|
||||
}
|
||||
|
||||
columns.push([
|
||||
{
|
||||
header: gettext('Source'),
|
||||
dataIndex: 'source',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Destination'),
|
||||
dataIndex: 'dest',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Protocol'),
|
||||
dataIndex: 'proto',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Dest. port'),
|
||||
dataIndex: 'dport',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Source port'),
|
||||
dataIndex: 'sport',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
header: gettext('Comment'),
|
||||
dataIndex: 'comment',
|
||||
flex: 1,
|
||||
renderer: function(value) {
|
||||
return Ext.util.Format.htmlEncode(value);
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
selModel: sm,
|
||||
tbar: tbar,
|
||||
viewConfig: {
|
||||
plugins: [
|
||||
{
|
||||
ptype: 'gridviewdragdrop',
|
||||
dragGroup: 'FWRuleDDGroup',
|
||||
dropGroup: 'FWRuleDDGroup'
|
||||
}
|
||||
],
|
||||
listeners: {
|
||||
beforedrop: function(node, data, dropRec, dropPosition) {
|
||||
if (!dropRec) {
|
||||
return false; // empty view
|
||||
}
|
||||
var moveto = dropRec.get('pos');
|
||||
if (dropPosition === 'after') {
|
||||
moveto++;
|
||||
}
|
||||
var pos = data.records[0].get('pos');
|
||||
me.moveRule(pos, moveto);
|
||||
return 0;
|
||||
},
|
||||
itemdblclick: run_editor
|
||||
}
|
||||
},
|
||||
columns: columns
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (me.base_url) {
|
||||
me.setBaseUrl(me.base_url); // load
|
||||
}
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('pve-fw-rule', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ { name: 'enable', type: 'boolean' },
|
||||
'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
|
||||
'dport', 'sport', 'comment', 'pos', 'digest' ],
|
||||
idProperty: 'pos'
|
||||
});
|
||||
|
||||
});
|
78
www/manager/panel/Firewall.js
Normal file
78
www/manager/panel/Firewall.js
Normal file
@ -0,0 +1,78 @@
|
||||
Ext.define('PVE.panel.Firewall', {
|
||||
extend: 'PVE.panel.SubConfig',
|
||||
alias: 'widget.pveFirewallPanel',
|
||||
|
||||
configPrefix: 'firewall',
|
||||
|
||||
fwtype: undefined, // 'dc', 'node' or 'vm'
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!me.base_url) {
|
||||
throw "no base_url specified";
|
||||
}
|
||||
|
||||
if (!(me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm')) {
|
||||
throw "unknown firewall panel type";
|
||||
}
|
||||
|
||||
var items = [
|
||||
{
|
||||
xtype: 'pveFirewallRules',
|
||||
title: 'Rules',
|
||||
allow_iface: true,
|
||||
base_url: me.base_url + '/rules',
|
||||
itemId: 'rules'
|
||||
}
|
||||
];
|
||||
|
||||
if (me.fwtype === 'dc') {
|
||||
items.push({
|
||||
xtype: 'pveSecurityGroups',
|
||||
title: 'Security Groups',
|
||||
itemId: 'sg'
|
||||
});
|
||||
items.push({
|
||||
xtype: 'pveFirewallAliases',
|
||||
base_url: '/cluster/firewall/aliases',
|
||||
itemId: 'aliases'
|
||||
});
|
||||
items.push({
|
||||
xtype: 'pveIPSet',
|
||||
base_url: '/cluster/firewall/ipset',
|
||||
itemId: 'ipset'
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
xtype: 'pveFirewallOptions',
|
||||
title: 'Options',
|
||||
base_url: me.base_url + '/options',
|
||||
fwtype: me.fwtype,
|
||||
itemId: 'options'
|
||||
});
|
||||
|
||||
if (me.fwtype !== 'dc') {
|
||||
items.push({
|
||||
title: 'Log',
|
||||
itemId: 'fwlog',
|
||||
xtype: 'pveLogView',
|
||||
url: '/api2/extjs' + me.base_url + '/log'
|
||||
});
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
defaults: {
|
||||
border: false,
|
||||
pveSelNode: me.pveSelNode
|
||||
},
|
||||
items: items
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
426
www/manager/panel/IPSet.js
Normal file
426
www/manager/panel/IPSet.js
Normal file
@ -0,0 +1,426 @@
|
||||
Ext.define('PVE.IPSetList', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: 'widget.pveIPSetList',
|
||||
|
||||
ipset_panel: undefined,
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
addBtn: undefined,
|
||||
removeBtn: undefined,
|
||||
editBtn: undefined,
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (me.ipset_panel == undefined) {
|
||||
throw "no rule panel specified";
|
||||
}
|
||||
|
||||
if (me.base_url == undefined) {
|
||||
throw "no base_url specified";
|
||||
}
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
fields: [ 'name', 'comment', 'digest' ],
|
||||
proxy: {
|
||||
type: 'pve',
|
||||
url: "/api2/json" + me.base_url
|
||||
},
|
||||
idProperty: 'name',
|
||||
sorters: {
|
||||
property: 'name',
|
||||
order: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var reload = function() {
|
||||
var oldrec = sm.getSelection()[0];
|
||||
store.load(function(records, operation, success) {
|
||||
if (oldrec) {
|
||||
var rec = store.findRecord('name', oldrec.data.name);
|
||||
if (rec) {
|
||||
sm.select(rec);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var run_editor = function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
var win = Ext.create('PVE.window.Edit', {
|
||||
subject: "IPSet '" + rec.data.name + "'",
|
||||
url: me.base_url,
|
||||
method: 'POST',
|
||||
digest: rec.data.digest,
|
||||
items: [
|
||||
{
|
||||
xtype: 'hiddenfield',
|
||||
name: 'rename',
|
||||
value: rec.data.name
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'name',
|
||||
value: rec.data.name,
|
||||
fieldLabel: gettext('Name'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: rec.data.comment,
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
]
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
me.editBtn = new PVE.button.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
selModel: sm,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
me.addBtn = new PVE.button.Button({
|
||||
text: gettext('Create'),
|
||||
handler: function() {
|
||||
sm.deselectAll();
|
||||
var win = Ext.create('PVE.window.Edit', {
|
||||
subject: 'IPSet',
|
||||
url: me.base_url,
|
||||
method: 'POST',
|
||||
items: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'name',
|
||||
value: '',
|
||||
fieldLabel: gettext('Name'),
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: '',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
]
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
me.removeBtn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec || !me.base_url) {
|
||||
return;
|
||||
}
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + rec.data.name,
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: reload
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
store: store,
|
||||
tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
|
||||
selModel: sm,
|
||||
columns: [
|
||||
{ header: 'IPSet', dataIndex: 'name', width: 100 },
|
||||
{ header: gettext('Comment'), dataIndex: 'comment', flex: 1 }
|
||||
],
|
||||
listeners: {
|
||||
itemdblclick: run_editor,
|
||||
select: function(sm, rec) {
|
||||
var url = me.base_url + '/' + rec.data.name;
|
||||
me.ipset_panel.setBaseUrl(url);
|
||||
},
|
||||
deselect: function() {
|
||||
me.ipset_panel.setBaseUrl(undefined);
|
||||
},
|
||||
show: reload
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
store.load();
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.IPSetCidrEdit', {
|
||||
extend: 'PVE.window.Edit',
|
||||
|
||||
cidr: undefined,
|
||||
|
||||
initComponent : function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
me.create = (me.cidr === undefined);
|
||||
|
||||
if (me.create) {
|
||||
me.url = '/api2/extjs' + me.base_url;
|
||||
me.method = 'POST';
|
||||
} else {
|
||||
me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
|
||||
me.method = 'PUT';
|
||||
}
|
||||
|
||||
var ipanel = Ext.create('PVE.panel.InputPanel', {
|
||||
create: me.create,
|
||||
column1: [
|
||||
{
|
||||
xtype: me.create ? 'textfield' : 'displayfield',
|
||||
name: 'cidr',
|
||||
height: 22, // hack: set same height as text fields
|
||||
value: '',
|
||||
fieldLabel: gettext('IP/CIDR')
|
||||
}
|
||||
],
|
||||
column2: [
|
||||
{
|
||||
xtype: 'pvecheckbox',
|
||||
name: 'nomatch',
|
||||
checked: false,
|
||||
height: 22, // hack: set same height as text fields
|
||||
uncheckedValue: 0,
|
||||
fieldLabel: gettext('nomatch')
|
||||
}
|
||||
],
|
||||
columnB: [
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'comment',
|
||||
value: '',
|
||||
fieldLabel: gettext('Comment')
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
subject: gettext('IP/CIDR'),
|
||||
items: [ ipanel ]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (!me.create) {
|
||||
me.load({
|
||||
success: function(response, options) {
|
||||
var values = response.result.data;
|
||||
ipanel.setValues(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ext.define('PVE.IPSetGrid', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: 'widget.pveIPSetGrid',
|
||||
|
||||
base_url: undefined,
|
||||
|
||||
addBtn: undefined,
|
||||
removeBtn: undefined,
|
||||
editBtn: undefined,
|
||||
|
||||
setBaseUrl: function(url) {
|
||||
var me = this;
|
||||
|
||||
me.base_url = url;
|
||||
|
||||
if (url === undefined) {
|
||||
me.addBtn.setDisabled(true);
|
||||
me.store.removeAll();
|
||||
} else {
|
||||
me.addBtn.setDisabled(false);
|
||||
me.store.setProxy({
|
||||
type: 'pve',
|
||||
url: '/api2/json' + url
|
||||
});
|
||||
|
||||
me.store.load();
|
||||
}
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
var store = new Ext.data.Store({
|
||||
model: 'pve-ipset'
|
||||
});
|
||||
|
||||
var reload = function() {
|
||||
store.load();
|
||||
};
|
||||
|
||||
var sm = Ext.create('Ext.selection.RowModel', {});
|
||||
|
||||
var run_editor = function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec) {
|
||||
return;
|
||||
}
|
||||
var win = Ext.create('PVE.IPSetCidrEdit', {
|
||||
base_url: me.base_url,
|
||||
cidr: rec.data.cidr
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
};
|
||||
|
||||
me.editBtn = new PVE.button.Button({
|
||||
text: gettext('Edit'),
|
||||
disabled: true,
|
||||
selModel: sm,
|
||||
handler: run_editor
|
||||
});
|
||||
|
||||
me.addBtn = new PVE.button.Button({
|
||||
text: gettext('Add'),
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
if (!me.base_url) {
|
||||
return;
|
||||
}
|
||||
var win = Ext.create('PVE.IPSetCidrEdit', {
|
||||
base_url: me.base_url
|
||||
});
|
||||
win.show();
|
||||
win.on('destroy', reload);
|
||||
}
|
||||
});
|
||||
|
||||
me.removeBtn = new PVE.button.Button({
|
||||
text: gettext('Remove'),
|
||||
selModel: sm,
|
||||
disabled: true,
|
||||
handler: function() {
|
||||
var rec = sm.getSelection()[0];
|
||||
if (!rec || !me.base_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
PVE.Utils.API2Request({
|
||||
url: me.base_url + '/' + rec.data.cidr,
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: me,
|
||||
failure: function(response, options) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: reload
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
|
||||
store: store,
|
||||
selModel: sm,
|
||||
listeners: {
|
||||
itemdblclick: run_editor
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
xtype: 'rownumberer'
|
||||
},
|
||||
{
|
||||
header: gettext('IP/CIDR'),
|
||||
dataIndex: 'cidr',
|
||||
width: 150,
|
||||
renderer: function(value, metaData, record) {
|
||||
if (record.data.nomatch) {
|
||||
return '<b>! </b>' + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
{
|
||||
header: gettext('Comment'),
|
||||
dataIndex: 'comment',
|
||||
flex: 1,
|
||||
renderer: function(value) {
|
||||
return Ext.util.Format.htmlEncode(value);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (me.base_url) {
|
||||
me.setBaseUrl(me.base_url); // load
|
||||
}
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.define('pve-ipset', {
|
||||
extend: 'Ext.data.Model',
|
||||
fields: [ { name: 'nomatch', type: 'boolean' },
|
||||
'cidr', 'comment' ],
|
||||
idProperty: 'cidr'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Ext.define('PVE.IPSet', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pveIPSet',
|
||||
|
||||
title: 'IPSet',
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
var ipset_panel = Ext.createWidget('pveIPSetGrid', {
|
||||
region: 'center',
|
||||
flex: 0.5,
|
||||
border: false
|
||||
});
|
||||
|
||||
var ipset_list = Ext.createWidget('pveIPSetList', {
|
||||
region: 'west',
|
||||
ipset_panel: ipset_panel,
|
||||
base_url: me.base_url,
|
||||
flex: 0.5,
|
||||
border: false,
|
||||
split: true
|
||||
});
|
||||
|
||||
Ext.apply(me, {
|
||||
layout: 'border',
|
||||
items: [ ipset_list, ipset_panel ],
|
||||
listeners: {
|
||||
show: function() {
|
||||
ipset_list.fireEvent('show', ipset_list);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
}
|
||||
});
|
80
www/manager/panel/SubConfigPanel.js
Normal file
80
www/manager/panel/SubConfigPanel.js
Normal file
@ -0,0 +1,80 @@
|
||||
Ext.define('PVE.panel.SubConfig', {
|
||||
extend: 'Ext.tab.Panel',
|
||||
alias: ['widget.pvePanelSubConfig'],
|
||||
|
||||
configPrefix: undefined,
|
||||
|
||||
getHState: function(itemId) {
|
||||
/*jslint confusion: true */
|
||||
var me = this;
|
||||
|
||||
if (!itemId) {
|
||||
itemId = me.getActiveTab().itemId;
|
||||
}
|
||||
|
||||
var first = me.items.get(0);
|
||||
var ntab;
|
||||
|
||||
// Note: '' is alias for first tab.
|
||||
if (itemId === first.itemId) {
|
||||
ntab = me.configPrefix;
|
||||
} else {
|
||||
ntab = me.configPrefix + '-' + itemId;
|
||||
}
|
||||
|
||||
return { value: ntab };
|
||||
},
|
||||
|
||||
initComponent: function() {
|
||||
var me = this;
|
||||
|
||||
if (!me.phstateid) {
|
||||
throw "no parent history state specified";
|
||||
}
|
||||
|
||||
var sp = Ext.state.Manager.getProvider();
|
||||
var state = sp.get(me.phstateid);
|
||||
|
||||
var hsregex = /^([^\-\s]+)-(\S+)?$/;
|
||||
|
||||
if (state && state.value) {
|
||||
var res = hsregex.exec(state.value);
|
||||
if (res && res[1] && res[2] && res[1] === me.configPrefix) {
|
||||
me.activeTab = res[2];
|
||||
}
|
||||
}
|
||||
|
||||
Ext.apply(me, {
|
||||
plain: true,
|
||||
tabPosition: 'bottom',
|
||||
listeners: {
|
||||
afterrender: function(tp) {
|
||||
var first = tp.items.get(0);
|
||||
if (first) {
|
||||
first.fireEvent('show', first);
|
||||
}
|
||||
},
|
||||
tabchange: function(tp, newcard, oldcard) {
|
||||
var state = me.getHState(newcard.itemId);
|
||||
sp.set(me.phstateid, state);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
me.callParent();
|
||||
|
||||
var statechange = function(sp, key, state) {
|
||||
if ((key === me.phstateid) && state) {
|
||||
var first = me.items.get(0);
|
||||
var atab = me.getActiveTab().itemId;
|
||||
var res = hsregex.exec(state.value);
|
||||
var ntab = (res && res[1]) ? res[1] : first.itemId;
|
||||
if (ntab && (atab != ntab)) {
|
||||
me.setActiveTab(ntab);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
me.mon(sp, 'statechange', statechange);
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user