mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 06:03:56 +08:00
🎨 Sync 2026-07-29 20:42:56
This commit is contained in:
1 parent
fc21fd8c5e
commit
93288fe344
11 files changed
+384
-257
No files matched your search
+2
-2
@@ -5,8 +5,8 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ddns-go
|
PKG_NAME:=ddns-go
|
||||||
PKG_VERSION:=6.17.2
|
PKG_VERSION:=6.17.3
|
||||||
PKG_RELEASE:=19
|
PKG_RELEASE:=20
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
|
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
|
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
|
||||||
|
|
||||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
|
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
|
||||||
PKG_RELEASE:=11
|
PKG_RELEASE:=12
|
||||||
|
|
||||||
LUCI_TITLE:=LuCI support for EasyTier
|
LUCI_TITLE:=LuCI support for EasyTier
|
||||||
LUCI_DEPENDS:=+kmod-tun +easytier +luci-compat
|
LUCI_DEPENDS:=+kmod-tun +easytier +luci-compat
|
||||||
|
|||||||
@@ -181,9 +181,11 @@ check_config() {
|
|||||||
LOG_SIZE=\$(ls -l /tmp/easytier.log | awk '{print int(\$5/1024)}')
|
LOG_SIZE=\$(ls -l /tmp/easytier.log | awk '{print int(\$5/1024)}')
|
||||||
if [ \$LOG_SIZE -gt 5120 ]; then
|
if [ \$LOG_SIZE -gt 5120 ]; then
|
||||||
tail -n 500 /tmp/easytier.log > /tmp/easytier.log.tmp
|
tail -n 500 /tmp/easytier.log > /tmp/easytier.log.tmp
|
||||||
mv /tmp/easytier.log.tmp /tmp/easytier.log
|
: > /tmp/easytier.log
|
||||||
|
cat /tmp/easytier.log.tmp >> /tmp/easytier.log
|
||||||
|
rm -f /tmp/easytier.log.tmp
|
||||||
fi
|
fi
|
||||||
sleep 300
|
sleep 60
|
||||||
done
|
done
|
||||||
} &
|
} &
|
||||||
LOG_MANAGEMENT_PID=\$!
|
LOG_MANAGEMENT_PID=\$!
|
||||||
@@ -604,9 +606,11 @@ EOF
|
|||||||
LOG_SIZE=\$(ls -l /tmp/easytier.log | awk '{print int(\$5/1024)}')
|
LOG_SIZE=\$(ls -l /tmp/easytier.log | awk '{print int(\$5/1024)}')
|
||||||
if [ \$LOG_SIZE -gt 5120 ]; then
|
if [ \$LOG_SIZE -gt 5120 ]; then
|
||||||
tail -n 500 /tmp/easytier.log > /tmp/easytier.log.tmp
|
tail -n 500 /tmp/easytier.log > /tmp/easytier.log.tmp
|
||||||
mv /tmp/easytier.log.tmp /tmp/easytier.log
|
: > /tmp/easytier.log
|
||||||
|
cat /tmp/easytier.log.tmp >> /tmp/easytier.log
|
||||||
|
rm -f /tmp/easytier.log.tmp
|
||||||
fi
|
fi
|
||||||
sleep 300
|
sleep 60
|
||||||
done
|
done
|
||||||
} &
|
} &
|
||||||
LOG_MANAGEMENT_PID=\$!
|
LOG_MANAGEMENT_PID=\$!
|
||||||
@@ -753,9 +757,11 @@ start_web() {
|
|||||||
LOG_SIZE=\$(ls -l /tmp/easytierweb.log | awk '{print int(\$5/1024)}')
|
LOG_SIZE=\$(ls -l /tmp/easytierweb.log | awk '{print int(\$5/1024)}')
|
||||||
if [ \$LOG_SIZE -gt 5120 ]; then
|
if [ \$LOG_SIZE -gt 5120 ]; then
|
||||||
tail -n 500 /tmp/easytierweb.log > /tmp/easytierweb.log.tmp
|
tail -n 500 /tmp/easytierweb.log > /tmp/easytierweb.log.tmp
|
||||||
mv /tmp/easytierweb.log.tmp /tmp/easytierweb.log
|
: > /tmp/easytierweb.log
|
||||||
|
cat /tmp/easytierweb.log.tmp >> /tmp/easytierweb.log
|
||||||
|
rm -f /tmp/easytierweb.log.tmp
|
||||||
fi
|
fi
|
||||||
sleep 300
|
sleep 60
|
||||||
done
|
done
|
||||||
} &
|
} &
|
||||||
LOG_MANAGEMENT_PID=\$!
|
LOG_MANAGEMENT_PID=\$!
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ LUCI_TITLE:=Web UI for QEMU Virtual Machine Simple (VMS)
|
|||||||
LUCI_DEPENDS:=@TARGET_x86_64 +qemu-vms +ttyd +usbutils +pciutils
|
LUCI_DEPENDS:=@TARGET_x86_64 +qemu-vms +ttyd +usbutils +pciutils
|
||||||
PKG_LICENSE:=GPLv3
|
PKG_LICENSE:=GPLv3
|
||||||
PKG_VERSION:=0.0.1
|
PKG_VERSION:=0.0.1
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
|
|
||||||
include $(TOPDIR)/feeds/luci/luci.mk
|
include $(TOPDIR)/feeds/luci/luci.mk
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,30 @@
|
|||||||
'require form';
|
'require form';
|
||||||
'require view';
|
'require view';
|
||||||
'require uci';
|
'require uci';
|
||||||
|
'require rpc';
|
||||||
|
|
||||||
|
var callListNetDrivers = rpc.declare({
|
||||||
|
object: 'luci.qemu-vms',
|
||||||
|
method: 'list_net_drivers',
|
||||||
|
params: []
|
||||||
|
});
|
||||||
|
|
||||||
function randomMac() {
|
function randomMac() {
|
||||||
// OUI 52:54:00:31 is our virtual-cluster prefix (matches manually
|
|
||||||
// assigned MACs used elsewhere in this config).
|
|
||||||
var b1 = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
|
var b1 = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
|
||||||
var b2 = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
|
var b2 = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
|
||||||
return '52:54:00:31:%s:%s'.format(b1, b2);
|
return '52:54:00:31:%s:%s'.format(b1, b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
render: function() {
|
load: function() {
|
||||||
|
return Promise.all([
|
||||||
|
callListNetDrivers(),
|
||||||
|
uci.load('qemu-vms')
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(data) {
|
||||||
|
var drivers = data[0].drivers || [];
|
||||||
var m, s;
|
var m, s;
|
||||||
|
|
||||||
m = new form.Map('qemu-vms', _('Virtual network segments'),
|
m = new form.Map('qemu-vms', _('Virtual network segments'),
|
||||||
@@ -26,10 +39,9 @@ return view.extend({
|
|||||||
s.nodescriptions = true;
|
s.nodescriptions = true;
|
||||||
|
|
||||||
var mac = s.option(form.Value, 'mac', _('MAC address'));
|
var mac = s.option(form.Value, 'mac', _('MAC address'));
|
||||||
//mac.placeholder = _('leave empty to auto-generate 52:54:00:31:xx:xx');
|
|
||||||
mac.validate = function(section_id, value) {
|
mac.validate = function(section_id, value) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return true; // filled in by write() below if left empty
|
return true;
|
||||||
if (!/^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/.test(value))
|
if (!/^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/.test(value))
|
||||||
return _('Invalid MAC address format (expected xx:xx:xx:xx:xx:xx)');
|
return _('Invalid MAC address format (expected xx:xx:xx:xx:xx:xx)');
|
||||||
return true;
|
return true;
|
||||||
@@ -41,7 +53,6 @@ return view.extend({
|
|||||||
};
|
};
|
||||||
mac.rmempty = false;
|
mac.rmempty = false;
|
||||||
mac.value(randomMac(), _('Automatically assigned'));
|
mac.value(randomMac(), _('Automatically assigned'));
|
||||||
//mac.editable = true;
|
|
||||||
|
|
||||||
var ifname = s.option(form.Value, 'ifname', _('tap ifname'));
|
var ifname = s.option(form.Value, 'ifname', _('tap ifname'));
|
||||||
ifname.placeholder = 'tap0';
|
ifname.placeholder = 'tap0';
|
||||||
@@ -55,6 +66,20 @@ return view.extend({
|
|||||||
var bridge = s.option(form.Value, 'bridge', _('Bridge (optional)'));
|
var bridge = s.option(form.Value, 'bridge', _('Bridge (optional)'));
|
||||||
bridge.placeholder = _('leave empty to keep the interface standalone');
|
bridge.placeholder = _('leave empty to keep the interface standalone');
|
||||||
|
|
||||||
|
// --- Поле driver с динамическим списком ---
|
||||||
|
var driver = s.option(form.ListValue, 'driver', _('Network driver'));
|
||||||
|
// Добавляем опции из загруженного списка
|
||||||
|
if (drivers.length) {
|
||||||
|
drivers.forEach(function(d) {
|
||||||
|
driver.value(d, d);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
driver.value('', _('No drivers found'));
|
||||||
|
}
|
||||||
|
driver.default = 'virtio-net-pci';
|
||||||
|
driver.rmempty = true;
|
||||||
|
driver.description = _('Choose the emulated network card model. If empty, virtio-net-pci is used.');
|
||||||
|
|
||||||
return m.render();
|
return m.render();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -12,6 +12,18 @@ var callStatus = rpc.declare({
|
|||||||
params: ['vm_name']
|
params: ['vm_name']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var callListMachines = rpc.declare({
|
||||||
|
object: 'luci.qemu-vms',
|
||||||
|
method: 'list_machines',
|
||||||
|
params: []
|
||||||
|
});
|
||||||
|
|
||||||
|
var callListCpus = rpc.declare({
|
||||||
|
object: 'luci.qemu-vms',
|
||||||
|
method: 'list_cpus',
|
||||||
|
params: []
|
||||||
|
});
|
||||||
|
|
||||||
var callStart = rpc.declare({ object: 'luci.qemu-vms', method: 'start', params: ['vm_name'] });
|
var callStart = rpc.declare({ object: 'luci.qemu-vms', method: 'start', params: ['vm_name'] });
|
||||||
var callStop = rpc.declare({ object: 'luci.qemu-vms', method: 'stop', params: ['vm_name'] });
|
var callStop = rpc.declare({ object: 'luci.qemu-vms', method: 'stop', params: ['vm_name'] });
|
||||||
var callRestart = rpc.declare({ object: 'luci.qemu-vms', method: 'restart', params: ['vm_name'] });
|
var callRestart = rpc.declare({ object: 'luci.qemu-vms', method: 'restart', params: ['vm_name'] });
|
||||||
@@ -36,6 +48,83 @@ function widenModal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ДЛЯ ПОСТРОЕНИЯ СЕЛЕКТОВ -----
|
||||||
|
|
||||||
|
function buildMachineSelect(vm, machines) {
|
||||||
|
var select = E('select', { 'class': 'cbi-input-select', 'id': 'edit-machine' });
|
||||||
|
machines.forEach(function(m) {
|
||||||
|
var opt = E('option', { 'value': m });
|
||||||
|
if (m === (vm.machine || 'q35')) opt.selected = true;
|
||||||
|
opt.textContent = m;
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
if (vm.machine && !machines.includes(vm.machine)) {
|
||||||
|
var opt = E('option', { 'value': vm.machine, 'selected': true });
|
||||||
|
opt.textContent = vm.machine + ' (custom)';
|
||||||
|
select.appendChild(opt);
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCpuSelect(vm, cpus) {
|
||||||
|
var baseCpus = ['host', 'max', 'qemu64', 'Haswell', 'Skylake-Client'];
|
||||||
|
var select = E('select', { 'class': 'cbi-input-select', 'id': 'edit-cpu' });
|
||||||
|
|
||||||
|
baseCpus.forEach(function(c) {
|
||||||
|
var opt = E('option', { 'value': c });
|
||||||
|
if (c === (vm.cpu || 'host')) opt.selected = true;
|
||||||
|
opt.textContent = c;
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
cpus.forEach(function(c) {
|
||||||
|
if (baseCpus.indexOf(c) === -1) {
|
||||||
|
var opt = E('option', { 'value': c });
|
||||||
|
if (c === vm.cpu) opt.selected = true;
|
||||||
|
opt.textContent = c;
|
||||||
|
select.appendChild(opt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (vm.cpu && !baseCpus.includes(vm.cpu) && !cpus.includes(vm.cpu)) {
|
||||||
|
var opt = E('option', { 'value': vm.cpu, 'selected': true });
|
||||||
|
opt.textContent = vm.cpu + ' (custom)';
|
||||||
|
select.appendChild(opt);
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMachineSelectFallback(vm) {
|
||||||
|
var select = E('select', { 'class': 'cbi-input-select', 'id': 'edit-machine' }, [
|
||||||
|
E('option', { 'value': 'q35', 'selected': (vm.machine || 'q35') === 'q35' || null }, 'q35 (recommended)'),
|
||||||
|
E('option', { 'value': 'pc', 'selected': vm.machine === 'pc' || null }, 'pc (legacy)')
|
||||||
|
]);
|
||||||
|
if (vm.machine && vm.machine !== 'q35' && vm.machine !== 'pc') {
|
||||||
|
var opt = E('option', { 'value': vm.machine, 'selected': true });
|
||||||
|
opt.textContent = vm.machine + ' (custom)';
|
||||||
|
select.appendChild(opt);
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCpuSelectFallback(vm) {
|
||||||
|
var baseCpus = ['host', 'max', 'qemu64', 'Haswell', 'Skylake-Client'];
|
||||||
|
var select = E('select', { 'class': 'cbi-input-select', 'id': 'edit-cpu' });
|
||||||
|
baseCpus.forEach(function(c) {
|
||||||
|
var opt = E('option', { 'value': c });
|
||||||
|
if (c === (vm.cpu || 'host')) opt.selected = true;
|
||||||
|
opt.textContent = c;
|
||||||
|
select.appendChild(opt);
|
||||||
|
});
|
||||||
|
if (vm.cpu && !baseCpus.includes(vm.cpu)) {
|
||||||
|
var opt = E('option', { 'value': vm.cpu, 'selected': true });
|
||||||
|
opt.textContent = vm.cpu + ' (custom)';
|
||||||
|
select.appendChild(opt);
|
||||||
|
}
|
||||||
|
return select;
|
||||||
|
}
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
load: function() {
|
load: function() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
@@ -283,233 +372,166 @@ return view.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleEdit: function(name, ev) {
|
handleEdit: function(name, ev) {
|
||||||
|
var self = this;
|
||||||
var isNew = !name;
|
var isNew = !name;
|
||||||
var existingNameForReset = isNew ? null : name;
|
var existingNameForReset = isNew ? null : name;
|
||||||
var vm = isNew ? {} : (uci.get('qemu-vms', name) || {});
|
var vm = isNew ? {} : (uci.get('qemu-vms', name) || {});
|
||||||
|
|
||||||
var allNetworks = uci.sections('qemu-vms', 'network').map(function(s) { return s['.name']; });
|
function showEditModal(machineSelect, cpuSelect) {
|
||||||
var allPci = uci.sections('qemu-vms', 'pci-passthrough').map(function(s) { return s['.name']; });
|
var allNetworks = uci.sections('qemu-vms', 'network').map(function(s) { return s['.name']; });
|
||||||
var allUsb = uci.sections('qemu-vms', 'usb-passthrough').map(function(s) { return s['.name']; });
|
var allPci = uci.sections('qemu-vms', 'pci-passthrough').map(function(s) { return s['.name']; });
|
||||||
var attachedNetworks = [].concat(vm.network || []);
|
var allUsb = uci.sections('qemu-vms', 'usb-passthrough').map(function(s) { return s['.name']; });
|
||||||
var attachedUsb = [].concat(vm.usb_passthrough || []);
|
var attachedNetworks = [].concat(vm.network || []);
|
||||||
|
var attachedUsb = [].concat(vm.usb_passthrough || []);
|
||||||
|
|
||||||
var nameInput = E('input', {
|
var nameInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-name', 'value': name || '', 'disabled': isNew ? null : true, 'placeholder': isNew ? _('e.g. ap, test, vlan') : null });
|
||||||
'class': 'cbi-input-text',
|
var enabledInput = E('input', { 'type': 'checkbox', 'id': 'edit-enabled', 'checked': (vm.enabled !== '0') || null });
|
||||||
'id': 'edit-name',
|
var memoryInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-memory', 'type': 'number', 'min': '32', 'step': '32', 'value': vm.memory || '128' });
|
||||||
'value': name || '',
|
var smpInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-smp', 'type': 'number', 'min': '1', 'max': '16', 'step': '1', 'value': vm.smp || '1' });
|
||||||
'disabled': isNew ? null : true,
|
// cpuSelect и machineSelect переданы как аргументы
|
||||||
'placeholder': isNew ? _('e.g. ap, test, vlan') : null
|
|
||||||
});
|
|
||||||
|
|
||||||
var enabledInput = E('input', {
|
var imageInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-image', 'value': vm.image || '', 'placeholder': '/mnt/disk/vm/name.img' });
|
||||||
'type': 'checkbox',
|
var diskBusSelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-disk-bus' }, [
|
||||||
'id': 'edit-enabled',
|
E('option', { 'value': 'virtio', 'selected': (vm.disk_bus || 'virtio') === 'virtio' || null }, 'virtio (default)'),
|
||||||
'checked': (vm.enabled !== '0') || null
|
E('option', { 'value': 'ide', 'selected': vm.disk_bus === 'ide' || null }, 'IDE'),
|
||||||
});
|
E('option', { 'value': 'sata', 'selected': vm.disk_bus === 'sata' || null }, 'SATA/AHCI'),
|
||||||
|
E('option', { 'value': 'scsi', 'selected': vm.disk_bus === 'scsi' || null }, 'virtio-SCSI')
|
||||||
var memoryInput = E('input', {
|
|
||||||
'class': 'cbi-input-text',
|
|
||||||
'id': 'edit-memory',
|
|
||||||
'type': 'number',
|
|
||||||
'min': '32',
|
|
||||||
'step': '32',
|
|
||||||
'value': vm.memory || '128'
|
|
||||||
});
|
|
||||||
var smpInput = E('input', {
|
|
||||||
'class': 'cbi-input-text',
|
|
||||||
'id': 'edit-smp',
|
|
||||||
'type': 'number',
|
|
||||||
'min': '1',
|
|
||||||
'max': '16',
|
|
||||||
'step': '1',
|
|
||||||
'value': vm.smp || '1'
|
|
||||||
});
|
|
||||||
|
|
||||||
var cpuSelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-cpu' }, [
|
|
||||||
E('option', { 'value': 'host', 'selected': (vm.cpu || 'host') === 'host' || null }, 'host'),
|
|
||||||
E('option', { 'value': 'max', 'selected': vm.cpu === 'max' || null }, 'max'),
|
|
||||||
E('option', { 'value': 'qemu64', 'selected': vm.cpu === 'qemu64' || null }, 'qemu64'),
|
|
||||||
E('option', { 'value': 'Haswell', 'selected': vm.cpu === 'Haswell' || null }, 'Haswell'),
|
|
||||||
E('option', { 'value': 'Skylake-Client', 'selected': vm.cpu === 'Skylake-Client' || null }, 'Skylake-Client')
|
|
||||||
]);
|
|
||||||
|
|
||||||
var imageInput = E('input', {
|
|
||||||
'class': 'cbi-input-text',
|
|
||||||
'id': 'edit-image',
|
|
||||||
'value': vm.image || '',
|
|
||||||
'placeholder': '/mnt/disk/vm/name.img'
|
|
||||||
});
|
|
||||||
|
|
||||||
var diskBusSelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-disk-bus' }, [
|
|
||||||
E('option', { 'value': 'virtio', 'selected': (vm.disk_bus || 'virtio') === 'virtio' || null }, 'virtio (default, best performance, needs guest drivers)'),
|
|
||||||
E('option', { 'value': 'ide', 'selected': vm.disk_bus === 'ide' || null }, 'IDE (widest compatibility \u2014 old Windows/DOS/legacy kernels)'),
|
|
||||||
E('option', { 'value': 'sata', 'selected': vm.disk_bus === 'sata' || null }, 'SATA/AHCI'),
|
|
||||||
E('option', { 'value': 'scsi', 'selected': vm.disk_bus === 'scsi' || null }, 'virtio-SCSI')
|
|
||||||
]);
|
|
||||||
|
|
||||||
var cdromInput = E('input', {
|
|
||||||
'class': 'cbi-input-text',
|
|
||||||
'id': 'edit-cdrom',
|
|
||||||
'value': vm.cdrom || '',
|
|
||||||
'placeholder': _('optional, e.g. /mnt/disk/iso/installer.iso')
|
|
||||||
});
|
|
||||||
|
|
||||||
var existingCustomArgs = [].concat(vm.custom_arg || []);
|
|
||||||
var customArgsInput = E('textarea', {
|
|
||||||
'class': 'cbi-input-textarea',
|
|
||||||
'id': 'edit-custom-args',
|
|
||||||
'style': 'width: 100%; height: 6em; font-family: monospace;',
|
|
||||||
'placeholder': _('one raw QEMU argument per line, e.g.\n-device usb-tablet\n-boot order=d')
|
|
||||||
}, existingCustomArgs.join('\n'));
|
|
||||||
|
|
||||||
var displaySelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-display' }, [
|
|
||||||
E('option', { 'value': 'serial', 'selected': (vm.display_type || 'serial') === 'serial' || null }, _('Serial console (ttyd)')),
|
|
||||||
E('option', { 'value': 'vnc', 'selected': vm.display_type === 'vnc' || null }, _('VNC (noVNC)'))
|
|
||||||
]);
|
|
||||||
|
|
||||||
var usedPorts = uci.sections('qemu-vms', 'vm')
|
|
||||||
.map(function(s) { return parseInt(s.vnc_port, 10); })
|
|
||||||
.filter(function(p) { return !isNaN(p); });
|
|
||||||
var suggestedPort = usedPorts.length ? Math.max.apply(null, usedPorts) + 1 : 5901;
|
|
||||||
|
|
||||||
var vncPortInput = E('input', {
|
|
||||||
'class': 'cbi-input-text',
|
|
||||||
'id': 'edit-vnc-port',
|
|
||||||
'type': 'number',
|
|
||||||
'min': '5900',
|
|
||||||
'value': vm.vnc_port || suggestedPort
|
|
||||||
});
|
|
||||||
|
|
||||||
var vncPortRow = E('div', { 'class': 'cbi-value', 'id': 'edit-vnc-port-row' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('VNC port (RFB, 5900+)')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, [
|
|
||||||
vncPortInput,
|
|
||||||
E('p', { 'class': 'cbi-value-description' },
|
|
||||||
_('Serves noVNC over websocket on port %s.').format('+1000'))
|
|
||||||
])
|
|
||||||
]);
|
|
||||||
|
|
||||||
displaySelect.addEventListener('change', function() {
|
|
||||||
vncPortRow.style.display = (displaySelect.value === 'vnc') ? '' : 'none';
|
|
||||||
});
|
|
||||||
vncPortRow.style.display = ((vm.display_type || 'serial') === 'vnc') ? '' : 'none';
|
|
||||||
|
|
||||||
var pciSelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-pci' }, [
|
|
||||||
E('option', { 'value': '', 'selected': !vm.pci_passthrough || null }, _('-- none --'))
|
|
||||||
].concat(allPci.map(function(p) {
|
|
||||||
return E('option', { 'value': p, 'selected': vm.pci_passthrough === p || null }, p);
|
|
||||||
})));
|
|
||||||
|
|
||||||
var networkChecks = allNetworks.map(function(net) {
|
|
||||||
return E('div', {}, [
|
|
||||||
E('label', {}, [
|
|
||||||
E('input', {
|
|
||||||
'type': 'checkbox',
|
|
||||||
'class': 'edit-network-check',
|
|
||||||
'value': net,
|
|
||||||
'checked': attachedNetworks.indexOf(net) !== -1 || null
|
|
||||||
}),
|
|
||||||
' ' + net
|
|
||||||
])
|
|
||||||
]);
|
]);
|
||||||
});
|
var cdromInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-cdrom', 'value': vm.cdrom || '', 'placeholder': _('optional, e.g. /mnt/disk/iso/installer.iso') });
|
||||||
|
var customArgsInput = E('textarea', { 'class': 'cbi-input-textarea', 'id': 'edit-custom-args', 'style': 'width: 100%; height: 6em; font-family: monospace;', 'placeholder': _('one raw QEMU argument per line') }, ([].concat(vm.custom_arg || [])).join('\n'));
|
||||||
|
|
||||||
if (!allNetworks.length)
|
var displaySelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-display' }, [
|
||||||
networkChecks = [E('em', {}, _('No networks defined yet \u2014 add some on the Networks tab.'))];
|
E('option', { 'value': 'serial', 'selected': (vm.display_type || 'serial') === 'serial' || null }, _('Serial console (ttyd)')),
|
||||||
|
E('option', { 'value': 'vnc', 'selected': vm.display_type === 'vnc' || null }, _('VNC (noVNC)'))
|
||||||
var usbSelect = E('div', {
|
|
||||||
'style': 'display: flex; flex-wrap: wrap; gap: 0.3em 1.2em;'
|
|
||||||
}, allUsb.map(function(usb) {
|
|
||||||
return E('label', { 'style': 'white-space: nowrap; font-weight: normal;' }, [
|
|
||||||
E('input', {
|
|
||||||
'type': 'checkbox',
|
|
||||||
'class': 'edit-usb-check',
|
|
||||||
'value': usb,
|
|
||||||
'checked': attachedUsb.indexOf(usb) !== -1 || null
|
|
||||||
}),
|
|
||||||
' ' + usb
|
|
||||||
]);
|
]);
|
||||||
}));
|
|
||||||
|
|
||||||
if (!allUsb.length)
|
var usedPorts = uci.sections('qemu-vms', 'vm').map(function(s) { return parseInt(s.vnc_port, 10); }).filter(function(p) { return !isNaN(p); });
|
||||||
usbSelect = E('em', {}, _('No USB passthrough sections defined yet \u2014 add some on the Hardware passthrough tab.'));
|
var suggestedPort = usedPorts.length ? Math.max.apply(null, usedPorts) + 1 : 5901;
|
||||||
|
var vncPortInput = E('input', { 'class': 'cbi-input-text', 'id': 'edit-vnc-port', 'type': 'number', 'min': '5900', 'value': vm.vnc_port || suggestedPort });
|
||||||
|
var vncPortRow = E('div', { 'class': 'cbi-value', 'id': 'edit-vnc-port-row' }, [
|
||||||
ui.showModal(isNew ? _('Add VM') : _('Edit %s').format(name), [
|
E('label', { 'class': 'cbi-value-title' }, _('VNC port (RFB, 5900+)')),
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Name')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, nameInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Enabled')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, enabledInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Memory (MB)')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, memoryInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('SMP (vCPUs)')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, smpInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('CPU model')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, cpuSelect)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Disk image path')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, imageInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Disk bus')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, diskBusSelect)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('CD-ROM (ISO)')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, cdromInput)
|
|
||||||
]),
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Custom QEMU arguments')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, [
|
E('div', { 'class': 'cbi-value-field' }, [
|
||||||
customArgsInput,
|
vncPortInput,
|
||||||
E('p', { 'class': 'cbi-value-description' },
|
E('p', { 'class': 'cbi-value-description' }, _('Serves noVNC over websocket on port %s.').format('+1000'))
|
||||||
_('Escape hatch for flags with no dedicated field \u2014 appended verbatim to the qemu-system-x86_64 command line.'))
|
|
||||||
])
|
])
|
||||||
]),
|
]);
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
displaySelect.addEventListener('change', function() {
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Console type')),
|
vncPortRow.style.display = (displaySelect.value === 'vnc') ? '' : 'none';
|
||||||
E('div', { 'class': 'cbi-value-field' }, displaySelect)
|
});
|
||||||
]),
|
vncPortRow.style.display = ((vm.display_type || 'serial') === 'vnc') ? '' : 'none';
|
||||||
vncPortRow,
|
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
var pciSelect = E('select', { 'class': 'cbi-input-select', 'id': 'edit-pci' }, [
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('PCI passthrough')),
|
E('option', { 'value': '', 'selected': !vm.pci_passthrough || null }, _('-- none --'))
|
||||||
E('div', { 'class': 'cbi-value-field' }, pciSelect)
|
].concat(allPci.map(function(p) {
|
||||||
]),
|
return E('option', { 'value': p, 'selected': vm.pci_passthrough === p || null }, p);
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
})));
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('USB passthrough')),
|
|
||||||
E('div', { 'class': 'cbi-value-field' }, usbSelect)
|
var networkChecks = allNetworks.map(function(net) {
|
||||||
]),
|
return E('div', {}, [
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
E('label', {}, [
|
||||||
E('label', { 'class': 'cbi-value-title' }, _('Attached networks')),
|
E('input', { 'type': 'checkbox', 'class': 'edit-network-check', 'value': net, 'checked': attachedNetworks.indexOf(net) !== -1 || null }),
|
||||||
E('div', { 'class': 'cbi-value-field' }, networkChecks)
|
' ' + net
|
||||||
]),
|
])
|
||||||
E('div', { 'class': 'cbi-value' }, [
|
]);
|
||||||
E('p', { 'class': 'cbi-value-description' }, _('Changes will take effect after restarting the VM.'))
|
});
|
||||||
]),
|
if (!allNetworks.length) networkChecks = [E('em', {}, _('No networks defined yet'))];
|
||||||
E('div', { 'class': 'right', 'style': 'margin-top: 1em' }, [
|
|
||||||
E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Cancel')),
|
var usbSelect = E('div', { 'style': 'display: flex; flex-wrap: wrap; gap: 0.3em 1.2em;' }, allUsb.map(function(usb) {
|
||||||
' ',
|
return E('label', { 'style': 'white-space: nowrap; font-weight: normal;' }, [
|
||||||
E('button', {
|
E('input', { 'type': 'checkbox', 'class': 'edit-usb-check', 'value': usb, 'checked': attachedUsb.indexOf(usb) !== -1 || null }),
|
||||||
'class': 'btn',
|
' ' + usb
|
||||||
'click': ui.createHandlerFn(this, 'handleEdit', existingNameForReset)
|
]);
|
||||||
}, _('Reset')),
|
}));
|
||||||
' ',
|
if (!allUsb.length) usbSelect = E('em', {}, _('No USB passthrough sections defined yet'));
|
||||||
E('button', {
|
|
||||||
'class': 'btn cbi-button-positive',
|
ui.showModal(isNew ? _('Add VM') : _('Edit %s').format(name), [
|
||||||
'click': ui.createHandlerFn(this, 'saveEdit', isNew ? null : name)
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
}, _('Save'))
|
E('label', { 'class': 'cbi-value-title' }, _('Name')),
|
||||||
])
|
E('div', { 'class': 'cbi-value-field' }, nameInput)
|
||||||
]);
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Enabled')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, enabledInput)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Memory (MB)')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, memoryInput)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('SMP (vCPUs)')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, smpInput)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('CPU model')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, cpuSelect)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Machine type')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, machineSelect)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Disk image path')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, imageInput)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Disk bus')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, diskBusSelect)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('CD-ROM (ISO)')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, cdromInput)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Custom QEMU arguments')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, [
|
||||||
|
customArgsInput,
|
||||||
|
E('p', { 'class': 'cbi-value-description' }, _('Escape hatch for flags with no dedicated field'))
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Console type')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, displaySelect)
|
||||||
|
]),
|
||||||
|
vncPortRow,
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('PCI passthrough')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, pciSelect)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('USB passthrough')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, usbSelect)
|
||||||
|
]),
|
||||||
|
E('div', { 'class': 'cbi-value' }, [
|
||||||
|
E('label', { 'class': 'cbi-value-title' }, _('Attached networks')),
|
||||||
|
E('div', { 'class': 'cbi-value-field' }, networkChecks)
|
||||||
|
]),
|
||||||
|
E('p', { 'class': 'cbi-section-descr', 'style': 'margin-top: 1em;' }, _('Changes will take effect after restarting the VM.')),
|
||||||
|
E('div', { 'class': 'right', 'style': 'margin-top: 1em' }, [
|
||||||
|
E('button', { 'class': 'btn', 'click': ui.hideModal }, _('Cancel')),
|
||||||
|
' ',
|
||||||
|
E('button', { 'class': 'btn', 'click': ui.createHandlerFn(self, 'handleEdit', existingNameForReset) }, _('Reset')),
|
||||||
|
' ',
|
||||||
|
E('button', { 'class': 'btn cbi-button-positive', 'click': ui.createHandlerFn(self, 'saveEdit', isNew ? null : name) }, _('Save'))
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.all([callListMachines(), callListCpus()])
|
||||||
|
.then(function(results) {
|
||||||
|
var machines = results[0].machines || [];
|
||||||
|
var cpus = results[1].cpus || [];
|
||||||
|
|
||||||
|
var machineSelect = buildMachineSelect(vm, machines);
|
||||||
|
var cpuSelect = buildCpuSelect(vm, cpus);
|
||||||
|
|
||||||
|
showEditModal(machineSelect, cpuSelect);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.warn('Failed to load machine/CPU lists, using fallback:', err.message);
|
||||||
|
var machineSelect = buildMachineSelectFallback(vm);
|
||||||
|
var cpuSelect = buildCpuSelectFallback(vm);
|
||||||
|
showEditModal(machineSelect, cpuSelect);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
saveEdit: function(existingName, ev) {
|
saveEdit: function(existingName, ev) {
|
||||||
@@ -555,6 +577,7 @@ return view.extend({
|
|||||||
uci.set('qemu-vms', name, 'memory', String(memory));
|
uci.set('qemu-vms', name, 'memory', String(memory));
|
||||||
uci.set('qemu-vms', name, 'smp', String(smp));
|
uci.set('qemu-vms', name, 'smp', String(smp));
|
||||||
uci.set('qemu-vms', name, 'cpu', document.getElementById('edit-cpu').value);
|
uci.set('qemu-vms', name, 'cpu', document.getElementById('edit-cpu').value);
|
||||||
|
uci.set('qemu-vms', name, 'machine', document.getElementById('edit-machine').value || 'q35');
|
||||||
uci.set('qemu-vms', name, 'image', document.getElementById('edit-image').value);
|
uci.set('qemu-vms', name, 'image', document.getElementById('edit-image').value);
|
||||||
uci.set('qemu-vms', name, 'disk_bus', document.getElementById('edit-disk-bus').value);
|
uci.set('qemu-vms', name, 'disk_bus', document.getElementById('edit-disk-bus').value);
|
||||||
|
|
||||||
@@ -605,8 +628,8 @@ return view.extend({
|
|||||||
// .map(function(el) { return el.value; });
|
// .map(function(el) { return el.value; });
|
||||||
//uci.set('qemu-vms', name, 'network', nets);
|
//uci.set('qemu-vms', name, 'network', nets);
|
||||||
|
|
||||||
var newUsb = Array.prototype.slice.call(document.querySelectorAll('.edit-usb-check:checked'))
|
//var newUsb = Array.prototype.slice.call(document.querySelectorAll('.edit-usb-check:checked'))
|
||||||
.map(function(el) { return el.value; });
|
// .map(function(el) { return el.value; });
|
||||||
|
|
||||||
var newNets = Array.prototype.slice.call(document.querySelectorAll('.edit-network-check:checked'))
|
var newNets = Array.prototype.slice.call(document.querySelectorAll('.edit-network-check:checked'))
|
||||||
.map(function(el) { return el.value; });
|
.map(function(el) { return el.value; });
|
||||||
@@ -635,3 +658,4 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -309,7 +309,10 @@ case "$1" in
|
|||||||
"readlog": { "vm_name": "", "lines": 0 },
|
"readlog": { "vm_name": "", "lines": 0 },
|
||||||
"console_open": { "vm_name": "" },
|
"console_open": { "vm_name": "" },
|
||||||
"console_close": { "vm_name": "" },
|
"console_close": { "vm_name": "" },
|
||||||
|
"list_cpus": { },
|
||||||
"list_hardware": { },
|
"list_hardware": { },
|
||||||
|
"list_machines": { },
|
||||||
|
"list_net_drivers": { },
|
||||||
"delete_vm": { "vm_name": "" }
|
"delete_vm": { "vm_name": "" }
|
||||||
}'
|
}'
|
||||||
;;
|
;;
|
||||||
@@ -366,6 +369,39 @@ case "$1" in
|
|||||||
list_hardware)
|
list_hardware)
|
||||||
list_hardware
|
list_hardware
|
||||||
;;
|
;;
|
||||||
|
list_machines)
|
||||||
|
machines=$(/usr/bin/qemu-system-x86_64 -M help 2>/dev/null | grep -E '^[a-zA-Z0-9_-]+' | grep -v Supported | awk '{print $1}')
|
||||||
|
json_init
|
||||||
|
json_add_array "machines"
|
||||||
|
for m in $machines; do
|
||||||
|
json_add_string "" "$m"
|
||||||
|
done
|
||||||
|
json_close_array
|
||||||
|
json_dump
|
||||||
|
;;
|
||||||
|
list_cpus)
|
||||||
|
cpus=$(/usr/bin/qemu-system-x86_64 -cpu help 2>/dev/null | \
|
||||||
|
awk '/^[[:space:]]*$/ || /Recognized/ {exit} {print $1}')
|
||||||
|
json_init
|
||||||
|
json_add_array "cpus"
|
||||||
|
for c in $cpus; do
|
||||||
|
json_add_string "" "$c"
|
||||||
|
done
|
||||||
|
json_close_array
|
||||||
|
json_dump
|
||||||
|
;;
|
||||||
|
list_net_drivers)
|
||||||
|
drivers=$(/usr/bin/qemu-system-x86_64 -device help 2>/dev/null | \
|
||||||
|
awk '/^Network devices:/{flag=1; next} /^[[:space:]]*$/{if(flag) exit} flag && /^name "[^"]+"/{print $2}' | \
|
||||||
|
sed -e 's/"//g' -e 's/,//g' )
|
||||||
|
json_init
|
||||||
|
json_add_array "drivers"
|
||||||
|
for d in $drivers; do
|
||||||
|
json_add_string "" "$d"
|
||||||
|
done
|
||||||
|
json_close_array
|
||||||
|
json_dump
|
||||||
|
;;
|
||||||
delete_vm)
|
delete_vm)
|
||||||
stop_vm_instance "$vm_name"
|
stop_vm_instance "$vm_name"
|
||||||
console_close "$vm_name" >/dev/null
|
console_close "$vm_name" >/dev/null
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
"restart",
|
"restart",
|
||||||
"console_open",
|
"console_open",
|
||||||
"console_close",
|
"console_close",
|
||||||
|
"list_machines",
|
||||||
|
"list_cpus",
|
||||||
|
"list_net_drivers",
|
||||||
"delete_vm"
|
"delete_vm"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=qemu-vms
|
PKG_NAME:=qemu-vms
|
||||||
PKG_VERSION:=0.0.1
|
PKG_VERSION:=0.0.1
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
|
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ _add_net() {
|
|||||||
config_get mac "$netcfg" mac
|
config_get mac "$netcfg" mac
|
||||||
config_get ifname "$netcfg" ifname
|
config_get ifname "$netcfg" ifname
|
||||||
config_get bridge "$netcfg" bridge
|
config_get bridge "$netcfg" bridge
|
||||||
|
config_get driver "$netcfg" driver "virtio-net-pci"
|
||||||
|
|
||||||
local id="net${idx}"
|
local id="net${idx}"
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ _add_net() {
|
|||||||
|
|
||||||
local mac_opt=""
|
local mac_opt=""
|
||||||
[ -n "$mac" ] && mac_opt=",mac=$mac"
|
[ -n "$mac" ] && mac_opt=",mac=$mac"
|
||||||
device_opts="$device_opts -device virtio-net-pci${mac_opt},netdev=$id"
|
device_opts="$device_opts -device ${driver}${mac_opt},netdev=$id"
|
||||||
idx=$((idx + 1))
|
idx=$((idx + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,25 +102,57 @@ _add_usb() {
|
|||||||
usb_needed=1
|
usb_needed=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#_unbind_usb_host() {
|
||||||
|
# local usbcfg="$1"
|
||||||
|
# local vendor_id product_id
|
||||||
|
# config_get vendor_id "$usbcfg" vendor_id
|
||||||
|
# config_get product_id "$usbcfg" product_id
|
||||||
|
# [ -n "$vendor_id" ] && [ -n "$product_id" ] || return 0
|
||||||
|
# for dev in /sys/bus/usb/devices/*; do
|
||||||
|
# if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
|
||||||
|
# local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
|
||||||
|
# if [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ]; then
|
||||||
|
# if [ -L "$dev/driver" ]; then
|
||||||
|
# local driver_path=$(readlink -f "$dev/driver")
|
||||||
|
# local driver_name=$(basename "$driver_path")
|
||||||
|
# echo -n "$(basename "$dev")" > "$driver_path/unbind" 2>/dev/null
|
||||||
|
# fi
|
||||||
|
# fi
|
||||||
|
# fi
|
||||||
|
# done
|
||||||
|
#}
|
||||||
|
|
||||||
_unbind_usb_host() {
|
_unbind_usb_host() {
|
||||||
local usbcfg="$1"
|
local usbcfg="$1"
|
||||||
local vendor_id product_id
|
local vendor_id product_id
|
||||||
config_get vendor_id "$usbcfg" vendor_id
|
config_get vendor_id "$usbcfg" vendor_id
|
||||||
config_get product_id "$usbcfg" product_id
|
config_get product_id "$usbcfg" product_id
|
||||||
[ -n "$vendor_id" ] && [ -n "$product_id" ] || return 0
|
logger -t qemu-vms "DEBUG unbind: usbcfg=$usbcfg vendor=$vendor_id product=$product_id"
|
||||||
for dev in /sys/bus/usb/devices/*; do
|
[ -n "$vendor_id" ] && [ -n "$product_id" ] || return 0
|
||||||
if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
|
for dev in /sys/bus/usb/devices/*; do
|
||||||
local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
|
if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
|
||||||
if [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ]; then
|
local v=$(cat "$dev/idVendor") p=$(cat "$dev/idProduct")
|
||||||
if [ -L "$dev/driver" ]; then
|
if [ "$v" = "$vendor_id" ] && [ "$p" = "$product_id" ]; then
|
||||||
local driver_path=$(readlink -f "$dev/driver")
|
local devname=$(basename "$dev")
|
||||||
local driver_name=$(basename "$driver_path")
|
if [ -L "$dev/driver" ]; then
|
||||||
echo -n "$(basename "$dev")" > "$driver_path/unbind" 2>/dev/null
|
local driver_path=$(readlink -f "$dev/driver")
|
||||||
host_log "$cfg" "USB: unbound $(basename "$dev") from $driver_name"
|
echo -n "$devname" > "$driver_path/unbind" 2>/dev/null
|
||||||
fi
|
host_log "$cfg" "USB: unbound $devname from $(basename "$driver_path")"
|
||||||
fi
|
fi
|
||||||
fi
|
# interfaces are SIBLINGS of $dev, not children -
|
||||||
done
|
# glob at the /sys/bus/usb/devices/ level, matching "$devname:*"
|
||||||
|
for iface in /sys/bus/usb/devices/"$devname":*; do
|
||||||
|
[ -e "$iface" ] || continue
|
||||||
|
if [ -L "$iface/driver" ]; then
|
||||||
|
local ifname=$(basename "$iface")
|
||||||
|
local idriver_path=$(readlink -f "$iface/driver")
|
||||||
|
echo -n "$ifname" > "$idriver_path/unbind" 2>/dev/null
|
||||||
|
host_log "$cfg" "USB: unbound $ifname from $(basename "$idriver_path")"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
build_customargs() {
|
build_customargs() {
|
||||||
@@ -209,6 +242,7 @@ start_vm() {
|
|||||||
config_get pci_passthrough "$cfg" pci_passthrough
|
config_get pci_passthrough "$cfg" pci_passthrough
|
||||||
config_get display_type "$cfg" display_type "serial"
|
config_get display_type "$cfg" display_type "serial"
|
||||||
config_get vnc_port "$cfg" vnc_port
|
config_get vnc_port "$cfg" vnc_port
|
||||||
|
config_get machine "$cfg" machine "q35"
|
||||||
|
|
||||||
local console_sock="/var/run/qemu-$cfg.sock"
|
local console_sock="/var/run/qemu-$cfg.sock"
|
||||||
local console_log="/var/log/qemu-$cfg-console.log"
|
local console_log="/var/log/qemu-$cfg-console.log"
|
||||||
@@ -242,7 +276,6 @@ start_vm() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test version PCI Pass
|
|
||||||
#local pci_id="" pci_opts=""
|
#local pci_id="" pci_opts=""
|
||||||
#if [ -n "$pci_passthrough" ]; then
|
#if [ -n "$pci_passthrough" ]; then
|
||||||
# config_get pci_id "$pci_passthrough" pci_id
|
# config_get pci_id "$pci_passthrough" pci_id
|
||||||
@@ -299,7 +332,7 @@ start_vm() {
|
|||||||
$disk_controller_opts $disk_opts \
|
$disk_controller_opts $disk_opts \
|
||||||
$device_opts $netdev_opts $pci_opts $cdrom_opts $usb_controller_opts $usb_opts $vnc_opts $custom_opts \
|
$device_opts $netdev_opts $pci_opts $cdrom_opts $usb_controller_opts $usb_opts $vnc_opts $custom_opts \
|
||||||
-device virtio-rng-pci \
|
-device virtio-rng-pci \
|
||||||
-machine q35 \
|
-machine $machine \
|
||||||
-chardev socket,id=con0,path="$console_sock",server=on,wait=off,logfile="$console_log",logappend=on \
|
-chardev socket,id=con0,path="$console_sock",server=on,wait=off,logfile="$console_log",logappend=on \
|
||||||
-serial chardev:con0 \
|
-serial chardev:con0 \
|
||||||
-chardev socket,id=qmp0,path="$qmp_sock",server=on,wait=off \
|
-chardev socket,id=qmp0,path="$qmp_sock",server=on,wait=off \
|
||||||
|
|||||||
+2
-2
@@ -5,8 +5,8 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=sing-box
|
PKG_NAME:=sing-box
|
||||||
PKG_VERSION:=1.13.14
|
PKG_VERSION:=1.13.15
|
||||||
PKG_RELEASE:=22
|
PKG_RELEASE:=23
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
|
PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
|
||||||
|
|||||||
Reference in new issue
Block a user