add firewall GUI classes

This commit is contained in:
Dietmar Maurer 2014-05-06 12:27:00 +02:00
parent 98282daade
commit 434f2466b4
7 changed files with 1925 additions and 0 deletions

View 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();
}
});

View 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);
}
});

View 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);
}
});

View 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'
});
});

View 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
View 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();
}
});

View 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);
}
});