Files
2026-02-21 22:33:23 +08:00

258 lines
6.9 KiB
JavaScript

'use strict';
'require form';
'require fs';
'require ui';
'require tools.widgets as widgets';
'require dockerman.common as dm2';
/*
Copyright 2026
Docker manager JS for Luci by Paul Donald <newtwen+github@gmail.com>
Based on Docker Lua by lisaac <https://github.com/lisaac/luci-app-dockerman>
LICENSE: GPLv2.0
*/
return dm2.dv.extend({
load() {
return Promise.all([
]);
},
render() {
// stuff JSONMap with {network: {}} to prime it with a new empty entry
const m = new form.JSONMap({network: {}}, _('Docker - New Network'));
m.submit = true;
m.reset = true;
let s = m.section(form.NamedSection, 'network', _('Create new docker network'));
s.anonymous = true;
s.nodescriptions = true;
s.addremove = false;
let o;
o = s.option(form.Value, 'name', _('Network Name'),
_('Name of the network that can be selected during container creation'));
o.rmempty = true;
o = s.option(form.ListValue, 'driver', _('Driver'));
o.rmempty = true;
o.value('bridge', _('Bridge device'));
o.value('macvlan', _('MAC VLAN'));
o.value('ipvlan', _('IP VLAN'));
o.value('overlay', _('Overlay network'));
o = s.option(widgets.DeviceSelect, 'parent', _('Base device'));
o.rmempty = true;
o.create = false
o.noaliases = true;
o.nocreate = true;
o.depends('driver', 'macvlan');
o = s.option(form.ListValue, 'macvlan_mode', _('Mode'));
o.rmempty = true;
o.depends('driver', 'macvlan');
o.default = 'bridge';
o.value('bridge', _('Bridge (Support direct communication between MAC VLANs)'));
o.value('private', _('Private (Prevent communication between MAC VLANs)'));
o.value('vepa', _('VEPA (Virtual Ethernet Port Aggregator)'));
o.value('passthru', _('Pass-through (Mirror physical device to single MAC VLAN)'));
o = s.option(form.ListValue, 'ipvlan_mode', _('Ipvlan Mode'));
o.rmempty = true;
o.depends('driver', 'ipvlan');
o.default='l3';
o.value('l2', _('L2 bridge'));
o.value('l3', _('L3 bridge'));
o = s.option(form.Flag, 'ingress',
_('Ingress'),
_('Ingress network is the network which provides the routing-mesh in swarm mode'));
o.rmempty = true;
o.disabled = 0;
o.enabled = 1;
o.default = 0;
o.depends('driver', 'overlay');
o = s.option(form.DynamicList, 'options', _('Options'));
o.rmempty = true;
o.placeholder='com.docker.network.driver.mtu=1500';
o = s.option(form.DynamicList, 'labels', _('Labels'));
o.rmempty = true;
o.placeholder='foo=bar';
o = s.option(form.Flag, 'internal', _('Internal'), _('Restrict external access to the network'));
o.rmempty = true;
o.depends('driver', 'overlay');
o.disabled = 0;
o.enabled = 1;
o.default = o.disabled;
// if nixio.fs.access('/etc/config/network') and nixio.fs.access('/etc/config/firewall')then
// o = s.option(form.Flag, 'op_macvlan', _('Create macvlan interface'), _('Auto create macvlan interface in Openwrt'))
// o.depends('driver', 'macvlan')
// o.disabled = 0
// o.enabled = 1
// o.default = 1
// end
o = s.option(form.Value, 'subnet', _('Subnet'));
o.rmempty = true;
o.placeholder = '10.1.0.0/16';
o.datatype = 'ip4addr';
o = s.option(form.Value, 'gateway', _('Gateway'));
o.rmempty = true;
o.placeholder = '10.1.1.1';
o.datatype = 'ip4addr';
o = s.option(form.Value, 'ip_range', _('IP range'));
o.rmempty = true;
o.placeholder='10.1.1.0/24';
o.datatype = 'ip4addr';
o = s.option(form.DynamicList, 'aux_address', _('Exclude IPs'));
o.rmempty = true;
o.placeholder = 'my-route=10.1.1.1';
o = s.option(form.Flag, 'ipv6', _('Enable IPv6'));
o.rmempty = true;
o.disabled = 0;
o.enabled = 1;
o.default = o.disabled;
o = s.option(form.Value, 'subnet6', _('IPv6 Subnet'));
o.rmempty = true;
o.placeholder='fe80::/10'
o.datatype = 'ip6addr';
o.depends('ipv6', 1);
o = s.option(form.Value, 'gateway6', _('IPv6 Gateway'));
o.rmempty = true;
o.placeholder='fe80::1';
o.datatype = 'ip6addr';
o.depends('ipv6', 1);
this.map = m;
return m.render();
},
handleSave(ev) {
ev?.preventDefault();
const view = this;
const map = this.map;
if (!map)
return Promise.reject(new Error(_('Form is not ready yet.')));
const listToKv = view.listToKv;
const toBool = (val) => (val === 1 || val === '1' || val === true);
return map.parse()
.then(() => {
const get = (opt) => map.data.get('json', 'network', opt);
const name = get('name');
const driver = get('driver');
const internal = toBool(get('internal'));
const ingress = toBool(get('ingress'));
const ipv6 = toBool(get('ipv6'));
const subnet = get('subnet');
const gateway = get('gateway');
const ipRange = get('ip_range');
const auxAddress = listToKv(get('aux_address'));
const optionsList = listToKv(get('options'));
const labelsList = listToKv(get('labels'));
const subnet6 = get('subnet6');
const gateway6 = get('gateway6');
const createBody = {
Name: name,
Driver: driver,
EnableIPv6: ipv6,
IPAM: {
Driver: 'default'
},
Internal: internal,
Labels: labelsList,
};
if (subnet || gateway || ipRange
|| (auxAddress && typeof auxAddress === 'object' && Object.keys(auxAddress).length)) {
createBody.IPAM.Config = [{
Subnet: subnet,
Gateway: gateway,
IPRange: ipRange,
AuxAddress: auxAddress,
AuxiliaryAddresses: auxAddress,
}];
}
if (driver === 'macvlan') {
createBody.Options = {
macvlan_mode: get('macvlan_mode'),
parent: get('parent'),
};
}
else if (driver === 'ipvlan') {
createBody.Options = {
ipvlan_mode: get('ipvlan_mode'),
};
}
else if (driver === 'overlay') {
createBody.Ingress = ingress;
}
if (ipv6 && (subnet6 || gateway6)) {
createBody.IPAM.Config = createBody.IPAM.Config || [];
createBody.IPAM.Config.push({
Subnet: subnet6,
Gateway: gateway6,
});
}
if (optionsList && typeof optionsList === 'object' && Object.keys(optionsList).length) {
createBody.Options = Object.assign(createBody.Options || {}, optionsList);
}
if (labelsList && typeof labelsList === 'object' && Object.keys(labelsList).length) {
createBody.Labels = Object.assign(createBody.Labels || {}, labelsList);
}
return createBody;
})
.then((createBody) => view.executeDockerAction(
dm2.network_create,
{ body: createBody },
_('Create network'),
{
showOutput: false,
showSuccess: false,
onSuccess: (response) => {
if (response?.body?.Warning) {
view.showNotification(_('Network created with warning'), response.body.Warning, 5000, 'warning');
} else {
view.showNotification(_('Network created'), _('OK'), 4000, 'success');
}
window.location.href = `${this.dockerman_url}/networks`;
}
}
))
.catch((err) => {
view.showNotification(_('Create network failed'), err?.message || String(err), 7000, 'error');
return false;
});
},
handleSaveApply: null,
handleReset: null,
});