mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-05 18:44:03 +08:00
317 lines
7.2 KiB
JavaScript
317 lines
7.2 KiB
JavaScript
'use strict';
|
|
|
|
'require baseclass';
|
|
'require network';
|
|
'require firewall';
|
|
'require uci';
|
|
'require ui';
|
|
|
|
'require podman.model.Model as Model';
|
|
|
|
const NetworkRPC = {
|
|
inspect: Model.declareRPC({
|
|
object: 'podman',
|
|
method: 'network_inspect',
|
|
params: ['name']
|
|
}),
|
|
|
|
remove: Model.declareRPC({
|
|
object: 'podman',
|
|
method: 'network_remove',
|
|
params: ['name', 'force']
|
|
}),
|
|
|
|
connect: Model.declareRPC({
|
|
object: 'podman',
|
|
method: 'network_connect',
|
|
params: ['name', 'data']
|
|
}),
|
|
|
|
disconnect: Model.declareRPC({
|
|
object: 'podman',
|
|
method: 'network_disconnect',
|
|
params: ['name', 'data']
|
|
}),
|
|
};
|
|
|
|
const Network = Model.base.extend({
|
|
__name__: 'Podman.Model.Network',
|
|
|
|
getID() {
|
|
return this.ID;
|
|
},
|
|
|
|
getName() {
|
|
return this.name || _('Unknown');
|
|
},
|
|
|
|
getDriver() {
|
|
return this.driver;
|
|
},
|
|
|
|
getSubnetIP4() {
|
|
if (this.subnets?.length > 0) {
|
|
return this.subnets[0].subnet || '';
|
|
}
|
|
if (this.IPAM?.Config?.length > 0) {
|
|
return this.IPAM.Config[0].Subnet || '';
|
|
}
|
|
return '';
|
|
},
|
|
|
|
getSubnetIP6() {
|
|
if (this.ipv6_enabled && this.subnets?.length > 1) {
|
|
return this.subnets[1].subnet || '';
|
|
}
|
|
return '';
|
|
},
|
|
|
|
getGatewayIP4() {
|
|
if (this.subnets?.length > 0) {
|
|
return this.subnets[0].gateway || '';
|
|
}
|
|
if (this.IPAM?.Config?.length > 0) {
|
|
return this.IPAM.Config[0].Gateway || '';
|
|
}
|
|
return '';
|
|
},
|
|
|
|
getGatewayIP6() {
|
|
if (this.ipv6_enabled && this.subnets?.length > 1) {
|
|
return this.subnets[1].gateway || '';
|
|
}
|
|
return '';
|
|
},
|
|
|
|
isBridge() {
|
|
return this.getDriver() === 'bridge';
|
|
},
|
|
|
|
async inspect() {
|
|
return NetworkRPC.inspect(this.getName());
|
|
},
|
|
|
|
async remove(force) {
|
|
return NetworkRPC.remove(this.getName(), force ?? false);
|
|
},
|
|
|
|
async connect(data) {
|
|
return NetworkRPC.connect(this.getName(), data || {});
|
|
},
|
|
|
|
async disconnect(data) {
|
|
return NetworkRPC.disconnect(this.getName(), data || {});
|
|
},
|
|
|
|
async integrationCheck() {
|
|
const check = {
|
|
hasInterface: false,
|
|
hasDevice: false,
|
|
hasDnsmasqExclusion: false,
|
|
};
|
|
|
|
const networkObj = await network.getNetwork(this.getName());
|
|
let deviceObj;
|
|
|
|
if (networkObj) {
|
|
check.hasInterface = true;
|
|
deviceObj = networkObj.getDevice();
|
|
|
|
if (deviceObj) {
|
|
check.hasDevice = true;
|
|
}
|
|
}
|
|
|
|
if (!deviceObj) {
|
|
const devices = (await network.getDevices()).map((device) => device.device);
|
|
|
|
if (devices.includes(this.network_interface)) {
|
|
check.hasDevice = true;
|
|
}
|
|
}
|
|
|
|
await uci.load('dhcp');
|
|
const mainSection = await this.hasDnsmasq() ? this._getDnsmasqSection() : null;
|
|
if (mainSection) {
|
|
const notInterfaces = uci.get('dhcp', mainSection, 'notinterface');
|
|
|
|
if ([].concat(notInterfaces ?? []).includes(this.getName())) {
|
|
check.hasDnsmasqExclusion = true;
|
|
}
|
|
} else {
|
|
check.hasDnsmasqExclusion = true;
|
|
}
|
|
|
|
return check;
|
|
},
|
|
|
|
async integrationRepair() {
|
|
await uci.load('dhcp');
|
|
const status = await this.integrationCheck();
|
|
if (status.hasInterface && status.hasDevice && status.hasDnsmasqExclusion) {
|
|
return;
|
|
}
|
|
|
|
let deviceName;
|
|
let changes = false;
|
|
|
|
if (status.hasDevice === false && this.isBridge()) {
|
|
deviceName = await this.integrationCreateDevice();
|
|
changes = true;
|
|
|
|
if (status.hasInterface === true) {
|
|
const net = await network.getNetwork(this.getName());
|
|
net.addDevice(deviceName);
|
|
}
|
|
}
|
|
|
|
if (status.hasInterface === false) {
|
|
if (status.hasDevice === true) {
|
|
deviceName = this.network_interface;
|
|
}
|
|
|
|
await this.integrationCreateNetwork(deviceName);
|
|
changes = true;
|
|
}
|
|
|
|
if (await this.hasDnsmasq() && status.hasDnsmasqExclusion === false) {
|
|
await this.integrationAddDnsmasqExclusion();
|
|
changes = true;
|
|
}
|
|
|
|
if (changes === false) {
|
|
return;
|
|
}
|
|
|
|
await uci.save();
|
|
ui.changes.apply();
|
|
await network.flushCache();
|
|
},
|
|
|
|
async integrationRemove() {
|
|
await uci.load('dhcp');
|
|
const status = await this.integrationCheck();
|
|
let changes = false;
|
|
|
|
// Check device shared status BEFORE deleting the interface to avoid stale network cache
|
|
let removeDevice = false;
|
|
if (status.hasDevice === true && this.isBridge()) {
|
|
const device = await network.getDevice(this.network_interface);
|
|
removeDevice = device?.getNetworks().length === 1;
|
|
}
|
|
|
|
if (status.hasInterface === true) {
|
|
const zone = await firewall.getZoneByNetwork(this.getName());
|
|
if (zone) await zone.deleteNetwork(this.getName());
|
|
await network.deleteNetwork(this.getName());
|
|
changes = true;
|
|
}
|
|
|
|
if (removeDevice) {
|
|
uci.remove('network', this.network_interface + '_device');
|
|
changes = true;
|
|
}
|
|
|
|
if (await this.hasDnsmasq() && status.hasDnsmasqExclusion === true) {
|
|
const mainSection = this._getDnsmasqSection();
|
|
if (mainSection) {
|
|
const notInterfaces = [].concat(uci.get('dhcp', mainSection, 'notinterface') || [])
|
|
.filter(iface => iface !== this.getName());
|
|
if (notInterfaces.length > 0)
|
|
uci.set('dhcp', mainSection, 'notinterface', notInterfaces);
|
|
else
|
|
uci.unset('dhcp', mainSection, 'notinterface');
|
|
changes = true;
|
|
}
|
|
}
|
|
|
|
if (changes === false) {
|
|
return;
|
|
}
|
|
|
|
await uci.save();
|
|
ui.changes.apply();
|
|
await network.flushCache();
|
|
},
|
|
|
|
async integrationCreateNetwork(deviceName) {
|
|
const networkName = this.getName();
|
|
|
|
if (this.subnets?.length === 0 && this.ipam_options?.driver === 'dhcp') {
|
|
uci.add('network', 'interface', networkName);
|
|
uci.set('network', networkName, 'proto', 'dhcp');
|
|
return;
|
|
}
|
|
|
|
const subnet = this.getSubnetIP4();
|
|
if (!subnet) return;
|
|
|
|
const prefix = parseInt(subnet.split('/')[1], 10);
|
|
const netmask = network.prefixToMask(prefix);
|
|
|
|
const sid = `${networkName}`;
|
|
uci.add('network', 'interface', sid);
|
|
uci.set('network', sid, 'proto', 'static');
|
|
if (deviceName) uci.set('network', sid, 'device', deviceName);
|
|
uci.set('network', sid, 'ipaddr', this.getGatewayIP4());
|
|
uci.set('network', sid, 'netmask', netmask);
|
|
|
|
if (this.ipv6_enabled) {
|
|
uci.set('network', sid, 'ip6addr', this.getGatewayIP6() + '/64');
|
|
}
|
|
},
|
|
|
|
async integrationCreateDevice() {
|
|
const devices = (await network.getDevices()).map((device) => device.device);
|
|
|
|
const baseName = this.network_interface || this.getName();
|
|
let i = 0;
|
|
let deviceName = baseName;
|
|
|
|
while (devices.includes(deviceName)) {
|
|
i++;
|
|
deviceName = `${baseName}${i}`;
|
|
}
|
|
|
|
const sid = `${deviceName}_device`;
|
|
uci.add('network', 'device', sid);
|
|
uci.set('network', sid, 'type', 'bridge');
|
|
uci.set('network', sid, 'name', deviceName);
|
|
uci.set('network', sid, 'bridge_empty', '1');
|
|
uci.set('network', sid, 'ipv6', this.ipv6_enabled ? '1' : '0');
|
|
|
|
if (this.ipv6_enabled) {
|
|
uci.set('network', sid, 'ip6assign', '64');
|
|
}
|
|
|
|
return deviceName;
|
|
},
|
|
|
|
_getDnsmasqSection() {
|
|
const sections = uci.sections('dhcp', 'dnsmasq');
|
|
return sections.length > 0 ? sections[0]['.name'] : null;
|
|
},
|
|
|
|
async hasDnsmasq() {
|
|
return L.hasSystemFeature('dnsmasq');
|
|
},
|
|
|
|
async integrationAddDnsmasqExclusion() {
|
|
const mainSection = this._getDnsmasqSection();
|
|
if (mainSection) {
|
|
const notInterfaces = [].concat(uci.get('dhcp', mainSection, 'notinterface') || []);
|
|
if (!notInterfaces.includes(this.getName())) {
|
|
notInterfaces.push(this.getName());
|
|
uci.set('dhcp', mainSection, 'notinterface', notInterfaces);
|
|
}
|
|
}
|
|
},
|
|
});
|
|
|
|
return baseclass.extend({
|
|
__name__: 'Podman.Model.Network',
|
|
getSingleton(data) {
|
|
return Network.extend(data).instantiate([]);
|
|
},
|
|
});
|