mirror of
https://github.com/AlbrechtL/openwrt-docker.git
synced 2026-10-15 16:01:25 +00:00
Adapt to aarch64, built in openwrt images and exclusiv Ethernet interfaces
This commit is contained in:
+16
-11
@@ -12,15 +12,18 @@ RUN apt-get update \
|
||||
nginx \
|
||||
swtpm \
|
||||
procps \
|
||||
iptables \
|
||||
iproute2 \
|
||||
apt-utils \
|
||||
dnsmasq \
|
||||
net-tools \
|
||||
qemu-utils \
|
||||
ca-certificates \
|
||||
netcat-openbsd \
|
||||
qemu-system-x86 \
|
||||
qemu-system-aarch64 \
|
||||
qemu-efi-aarch64 \
|
||||
ipxe-qemu \
|
||||
seabios \
|
||||
iputils-ping \
|
||||
iptables \
|
||||
iproute2 \
|
||||
isc-dhcp-client \
|
||||
&& apt-get clean \
|
||||
&& novnc="1.4.0" \
|
||||
&& mkdir -p /usr/share/novnc \
|
||||
@@ -38,13 +41,15 @@ COPY ./web /var/www/
|
||||
RUN chmod +x /run/*.sh
|
||||
RUN mv /var/www/nginx.conf /etc/nginx/sites-enabled/web.conf
|
||||
|
||||
VOLUME /storage
|
||||
EXPOSE 22 5900 8006
|
||||
# Get OpenWrt images
|
||||
RUN mkdir /var/vm
|
||||
RUN wget "https://archive.openwrt.org/releases/23.05.1/targets/armsr/armv8/openwrt-23.05.1-armsr-armv8-generic-ext4-rootfs.img.gz" \
|
||||
-O /var/vm/rootfs.img.gz
|
||||
RUN wget "https://archive.openwrt.org/releases/23.05.1/targets/armsr/armv8/openwrt-23.05.1-armsr-armv8-generic-kernel.bin" \
|
||||
-O /var/vm/kernel.bin
|
||||
|
||||
ENV CPU_CORES "1"
|
||||
ENV RAM_SIZE "1G"
|
||||
ENV DISK_SIZE "16G"
|
||||
ENV BOOT "http://example.com/image.iso"
|
||||
VOLUME /storage
|
||||
EXPOSE 8006
|
||||
|
||||
ARG VERSION_ARG "0.0"
|
||||
RUN echo "$VERSION_ARG" > /run/version
|
||||
|
||||
+9
-6
@@ -1,13 +1,12 @@
|
||||
version: "3"
|
||||
services:
|
||||
qemu:
|
||||
container_name: qemu
|
||||
image: qemux/qemu-docker
|
||||
container_name: openwrt-docker-arm64
|
||||
image: "openwrt-docker-arm64"
|
||||
environment:
|
||||
RAM_SIZE: "1G"
|
||||
CPU_CORES: "1"
|
||||
DISK_SIZE: "16G"
|
||||
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso"
|
||||
DEBUG: "y"
|
||||
WAN_IF: "enx00e04c0407a6"
|
||||
LAN_IF: "enx00e04d68033f"
|
||||
devices:
|
||||
- /dev/kvm
|
||||
device_cgroup_rules:
|
||||
@@ -18,3 +17,7 @@ services:
|
||||
- 8006:8006
|
||||
stop_grace_period: 2m
|
||||
restart: on-failure
|
||||
pid: "host"
|
||||
privileged: true
|
||||
volumes:
|
||||
- /dev:/dev/
|
||||
|
||||
@@ -1,217 +1,28 @@
|
||||
<h1 align="center">QEMU<br />
|
||||
<div align="center">
|
||||
<img src="https://github.com/qemus/qemu-docker/raw/master/.github/logo.png" title="Logo" style="max-width:100%;" width="128" />
|
||||
</div>
|
||||
<div align="center">
|
||||
# OpenWrt qemu docker container for arm64
|
||||
|
||||
[![Build]][build_url]
|
||||
[![Version]][tag_url]
|
||||
[![Size]][tag_url]
|
||||
[![Pulls]][hub_url]
|
||||
Based on the great works of https://github.com/qemus/qemu-docker. Thanks!
|
||||
|
||||
</div></h1>
|
||||
|
||||
QEMU in a docker container for running x64 virtual machines.
|
||||
QEMU in a docker container for running arm64 virtual machines. Tested on Raspberry Pi 5.
|
||||
|
||||
It uses high-performance QEMU options (like KVM acceleration, kernel-mode networking, IO threading, etc.) to achieve near-native speed.
|
||||
|
||||
Pre-build images can be found a docker hub (TBD)
|
||||
|
||||
## Features
|
||||
|
||||
- Multi-platform
|
||||
- KVM acceleration
|
||||
- Web-based viewer
|
||||
- Web-based viewer for tty console
|
||||
- Attaches two physical Ethernet interfaces exclusicly into the docker container
|
||||
|
||||
## Usage
|
||||
|
||||
Via `docker-compose.yml`
|
||||
See `docker-compose.yml`
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
qemu:
|
||||
container_name: qemu
|
||||
image: qemux/qemu-docker
|
||||
environment:
|
||||
BOOT: "https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/x86_64/alpine-virt-3.19.0-x86_64.iso"
|
||||
devices:
|
||||
- /dev/kvm
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
ports:
|
||||
- 8006:8006
|
||||
stop_grace_period: 2m
|
||||
restart: on-failure
|
||||
```
|
||||
## How it works
|
||||
See `src/entry.sh` and `Dockerfile`
|
||||
|
||||
Via `docker run`
|
||||
## Build and run
|
||||
|
||||
```bash
|
||||
docker run -it --rm -e "BOOT=http://example.com/image.iso" -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN qemux/qemu-docker
|
||||
docker build -t openwrt-docker-arm64 . && docker compose up
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
* ### How do I use it?
|
||||
|
||||
Very simple! These are the steps:
|
||||
|
||||
- Set the `BOOT` environment variable to the URL of an ISO image you want to install.
|
||||
|
||||
- Start the container and connect to [port 8006](http://localhost:8006) using your web browser.
|
||||
|
||||
- You will see the screen and can now install the OS of your choice using your keyboard and mouse.
|
||||
|
||||
Enjoy your brand new machine, and don't forget to star this repo!
|
||||
|
||||
* ### How do I increase the amount of CPU or RAM?
|
||||
|
||||
By default, a single CPU core and 1 GB of RAM are allocated to the container.
|
||||
|
||||
To increase this, add the following environment variables:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
RAM_SIZE: "4G"
|
||||
CPU_CORES: "4"
|
||||
```
|
||||
|
||||
* ### How do I change the size of the disk?
|
||||
|
||||
To expand the default size of 16 GB, add the `DISK_SIZE` setting to your compose file and set it to your preferred capacity:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
DISK_SIZE: "128G"
|
||||
```
|
||||
|
||||
This can also be used to resize the existing disk to a larger capacity without any data loss.
|
||||
|
||||
* ### How do I change the storage location?
|
||||
|
||||
To change the storage location, include the following bind mount in your compose file:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- /var/qemu:/storage
|
||||
```
|
||||
|
||||
Replace the example path `/var/qemu` with the desired storage folder.
|
||||
|
||||
* ### How do I boot Windows?
|
||||
|
||||
To enable Windows booting, add the following line to your compose file:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
BOOT_MODE: "windows"
|
||||
```
|
||||
|
||||
But you might want to give [dockur/windows](https://github.com/dockur/windows) a try instead, as it includes all the drivers required during installation and many other features.
|
||||
|
||||
* ### How do I verify if my system supports KVM?
|
||||
|
||||
To verify if your system supports KVM, run the following commands:
|
||||
|
||||
```bash
|
||||
sudo apt install cpu-checker
|
||||
sudo kvm-ok
|
||||
```
|
||||
|
||||
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS.
|
||||
|
||||
* ### How do I assign an individual IP address to the container?
|
||||
|
||||
By default, the container uses bridge networking, which shares the IP address with the host.
|
||||
|
||||
If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
|
||||
|
||||
```bash
|
||||
docker network create -d macvlan \
|
||||
--subnet=192.168.0.0/24 \
|
||||
--gateway=192.168.0.1 \
|
||||
--ip-range=192.168.0.100/28 \
|
||||
-o parent=eth0 vlan
|
||||
```
|
||||
|
||||
Be sure to modify these values to match your local subnet.
|
||||
|
||||
Once you have created the network, change your compose file to look as follows:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
qemu:
|
||||
container_name: qemu
|
||||
..<snip>..
|
||||
networks:
|
||||
vlan:
|
||||
ipv4_address: 192.168.0.100
|
||||
|
||||
networks:
|
||||
vlan:
|
||||
external: true
|
||||
```
|
||||
|
||||
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
|
||||
|
||||
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
|
||||
|
||||
* ### How can the VM acquire an IP address from my router?
|
||||
|
||||
After configuring the container for macvlan (see above), it is possible for the VM to become part of your home network by requesting an IP from your router, just like your other devices.
|
||||
|
||||
To enable this feature, add the following lines to your compose file:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
DHCP: "Y"
|
||||
device_cgroup_rules:
|
||||
- 'c *:* rwm'
|
||||
```
|
||||
|
||||
Please note that in this mode, the container and the VM will each have their own separate IPs. The container will keep the macvlan IP, and the VM will be reachable via the DHCP IP.
|
||||
|
||||
* ### How do I pass-through a disk?
|
||||
|
||||
It is possible to pass-through disk devices directly by adding them to your compose file in this way:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
DEVICE: "/dev/sda"
|
||||
DEVICE2: "/dev/sdb"
|
||||
devices:
|
||||
- /dev/sda
|
||||
- /dev/sdb
|
||||
```
|
||||
|
||||
Use `DEVICE` if you want it to become your main drive, and use `DEVICE2` and higher to add them as secondary drives.
|
||||
|
||||
* ### How do I boot with UEFI?
|
||||
|
||||
To enable UEFI booting, add the following line to your compose file:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
BOOT_MODE: "uefi"
|
||||
```
|
||||
|
||||
* ### How do I boot a local image?
|
||||
|
||||
To skip the download, rename your image to `boot.iso` and place it in an empty `/storage` folder.
|
||||
|
||||
* ### How do I provide custom arguments to QEMU?
|
||||
|
||||
You can create the `ARGUMENTS` environment variable to provide additional arguments to QEMU at runtime:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
ARGUMENTS: "-device usb-tablet"
|
||||
```
|
||||
|
||||
[build_url]: https://github.com/qemus/qemu-docker/
|
||||
[hub_url]: https://hub.docker.com/r/qemux/qemu-docker/
|
||||
[tag_url]: https://hub.docker.com/r/qemux/qemu-docker/tags
|
||||
|
||||
[Build]: https://github.com/qemus/qemu-docker/actions/workflows/build.yml/badge.svg
|
||||
[Size]: https://img.shields.io/docker/image-size/qemux/qemu-docker/latest?color=066da5&label=size
|
||||
[Pulls]: https://img.shields.io/docker/pulls/qemux/qemu-docker.svg?style=flat&label=pulls&logo=docker
|
||||
[Version]: https://img.shields.io/docker/v/qemux/qemu-docker/latest?arch=amd64&sort=semver&color=066da5
|
||||
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
: "${TPM:="Y"}" # Enable TPM
|
||||
: "${BOOT_MODE:="legacy"}" # Boot mode
|
||||
|
||||
SECURE=""
|
||||
BOOT_OPTS=""
|
||||
|
||||
case "${BOOT_MODE,,}" in
|
||||
uefi)
|
||||
ROM="OVMF_CODE_4M.fd"
|
||||
VARS="OVMF_VARS_4M.fd"
|
||||
;;
|
||||
secure)
|
||||
ROM="OVMF_CODE_4M.secboot.fd"
|
||||
VARS="OVMF_VARS_4M.secboot.fd"
|
||||
;;
|
||||
windows)
|
||||
ROM="OVMF_CODE_4M.ms.fd"
|
||||
VARS="OVMF_VARS_4M.ms.fd"
|
||||
;;
|
||||
windows_legacy)
|
||||
USB="usb-ehci"
|
||||
BOOT_OPTS=""
|
||||
;;
|
||||
legacy)
|
||||
BOOT_OPTS=""
|
||||
;;
|
||||
*)
|
||||
info "Unknown boot mode '${BOOT_MODE}', defaulting to 'legacy'"
|
||||
BOOT_MODE="legacy"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "${BOOT_MODE,,}" != "legacy" ]] && [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
|
||||
|
||||
OVMF="/usr/share/OVMF"
|
||||
DEST="$STORAGE/${BOOT_MODE,,}"
|
||||
|
||||
if [ ! -f "$DEST.rom" ]; then
|
||||
[ ! -f "$OVMF/$ROM" ] && error "UEFI boot file ($OVMF/$ROM) not found!" && exit 44
|
||||
cp "$OVMF/$ROM" "$DEST.rom"
|
||||
fi
|
||||
|
||||
if [ ! -f "$DEST.vars" ]; then
|
||||
[ ! -f "$OVMF/$VARS" ] && error "UEFI vars file ($OVMF/$VARS) not found!" && exit 45
|
||||
cp "$OVMF/$VARS" "$DEST.vars"
|
||||
fi
|
||||
|
||||
if [[ "${BOOT_MODE,,}" != "uefi" ]]; then
|
||||
SECURE=",smm=on"
|
||||
BOOT_OPTS="$BOOT_OPTS -global driver=cfi.pflash01,property=secure,value=on"
|
||||
fi
|
||||
|
||||
BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.rom,if=pflash,unit=0,format=raw,readonly=on"
|
||||
BOOT_OPTS="$BOOT_OPTS -drive file=$DEST.vars,if=pflash,unit=1,format=raw"
|
||||
|
||||
if [[ "${BOOT_MODE,,}" == "windows" ]]; then
|
||||
|
||||
BOOT_OPTS="$BOOT_OPTS -global kvm-pit.lost_tick_policy=discard -global ICH9-LPC.disable_s3=1"
|
||||
|
||||
if [[ "$TPM" == [Yy1]* ]]; then
|
||||
|
||||
rm -rf /run/shm/tpm
|
||||
rm -f /var/run/tpm.pid
|
||||
mkdir -p /run/shm/tpm
|
||||
chmod 755 /run/shm/tpm
|
||||
|
||||
if ! swtpm socket -t -d --tpmstate dir=/run/shm/tpm --ctrl type=unixio,path=/run/swtpm-sock --pid file=/var/run/tpm.pid --tpm2; then
|
||||
error "Failed to start TPM emulator, reason: $?" && exit 19
|
||||
fi
|
||||
|
||||
for (( i = 1; i < 20; i++ )); do
|
||||
|
||||
[ -S "/run/swtpm-sock" ] && break
|
||||
|
||||
if (( i % 10 == 0 )); then
|
||||
echo "Waiting for TPM socket to become available..."
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
|
||||
done
|
||||
|
||||
if [ ! -S "/run/swtpm-sock" ]; then
|
||||
TPM="N"
|
||||
error "TPM socket not found? Disabling TPM support..."
|
||||
else
|
||||
BOOT_OPTS="$BOOT_OPTS -chardev socket,id=chrtpm,path=/run/swtpm-sock"
|
||||
BOOT_OPTS="$BOOT_OPTS -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
return 0
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
: "${USB:="qemu-xhci"}"
|
||||
: "${SERIAL:="mon:stdio"}"
|
||||
: "${MONITOR:="telnet:localhost:7100,server,nowait,nodelay"}"
|
||||
|
||||
DEF_OPTS="-nodefaults"
|
||||
SERIAL_OPTS="-serial $SERIAL"
|
||||
MON_OPTS="-monitor $MONITOR"
|
||||
USB_OPTS="-device $USB -device usb-tablet"
|
||||
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
||||
CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
|
||||
MAC_OPTS="-machine type=q35${SECURE},graphics=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
|
||||
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
|
||||
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
|
||||
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
|
||||
|
||||
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $BOOT_OPTS $DEV_OPTS $USB_OPTS $ARGUMENTS"
|
||||
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
|
||||
|
||||
if [[ "${DISPLAY,,}" == "web" ]]; then
|
||||
[ ! -f "$INFO" ] && error "File $INFO not found?!"
|
||||
rm -f "$INFO"
|
||||
[ ! -f "$PAGE" ] && error "File $PAGE not found?!"
|
||||
rm -f "$PAGE"
|
||||
else
|
||||
if [[ "${DISPLAY,,}" == "vnc" ]]; then
|
||||
html "You can now connect to VNC on port 5900." "0"
|
||||
else
|
||||
html "The virtual machine was booted successfully." "0"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
-494
@@ -1,494 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
|
||||
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
|
||||
: "${DISK_FMT:=""}" # Disk file format, can be set to "raw" (default) or "qcow2"
|
||||
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
|
||||
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
|
||||
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
|
||||
: "${DISK_ROTATION:="1"}" # Rotation rate, set to 1 for SSD storage and increase for HDD
|
||||
|
||||
DISK_OPTS="-object iothread,id=io2"
|
||||
DISK_OPTS="$DISK_OPTS -device virtio-scsi-pci,id=scsi0,iothread=io2,addr=0x5"
|
||||
DISK_OPTS="$DISK_OPTS -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=$BOOT_INDEX"
|
||||
|
||||
BOOT="$STORAGE/$BASE"
|
||||
|
||||
if [ -f "$BOOT" ]; then
|
||||
DISK_OPTS="$DISK_OPTS -drive id=cdrom0,if=none,format=raw,readonly=on,file=$BOOT"
|
||||
else
|
||||
DISK_OPTS="$DISK_OPTS -drive id=cdrom0,if=none,format=raw,readonly=on,file=/dev/null"
|
||||
fi
|
||||
|
||||
DRIVERS="$STORAGE/drivers.iso"
|
||||
[ ! -f "$DRIVERS" ] && DRIVERS="/run/drivers.iso"
|
||||
|
||||
if [ -f "$DRIVERS" ]; then
|
||||
DISK_OPTS="$DISK_OPTS \
|
||||
-drive id=cdrom1,if=none,format=raw,readonly=on,file=$DRIVERS \
|
||||
-device ide-cd,drive=cdrom1"
|
||||
fi
|
||||
|
||||
fmt2ext() {
|
||||
local DISK_FMT=$1
|
||||
|
||||
case "${DISK_FMT,,}" in
|
||||
qcow2)
|
||||
echo "qcow2"
|
||||
;;
|
||||
raw)
|
||||
echo "img"
|
||||
;;
|
||||
*)
|
||||
error "Unrecognized disk format: $DISK_FMT" && exit 78
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
ext2fmt() {
|
||||
local DISK_EXT=$1
|
||||
|
||||
case "${DISK_EXT,,}" in
|
||||
qcow2)
|
||||
echo "qcow2"
|
||||
;;
|
||||
img)
|
||||
echo "raw"
|
||||
;;
|
||||
*)
|
||||
error "Unrecognized file extension: .$DISK_EXT" && exit 78
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
getSize() {
|
||||
local DISK_FILE=$1
|
||||
local DISK_EXT DISK_FMT
|
||||
|
||||
DISK_EXT=$(echo "${DISK_FILE//*./}" | sed 's/^.*\.//')
|
||||
DISK_FMT=$(ext2fmt "$DISK_EXT")
|
||||
|
||||
case "${DISK_FMT,,}" in
|
||||
raw)
|
||||
stat -c%s "$DISK_FILE"
|
||||
;;
|
||||
qcow2)
|
||||
qemu-img info "$DISK_FILE" -f "$DISK_FMT" | grep '^virtual size: ' | sed 's/.*(\(.*\) bytes)/\1/'
|
||||
;;
|
||||
*)
|
||||
error "Unrecognized disk format: $DISK_FMT" && exit 78
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
isCow() {
|
||||
local FS=$1
|
||||
|
||||
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
createDisk() {
|
||||
local DISK_FILE=$1
|
||||
local DISK_SPACE=$2
|
||||
local DISK_DESC=$3
|
||||
local DISK_FMT=$4
|
||||
local FS=$5
|
||||
local DATA_SIZE DIR SPACE FA
|
||||
|
||||
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
|
||||
|
||||
rm -f "$DISK_FILE"
|
||||
|
||||
if [[ "$ALLOCATE" != [Nn]* ]]; then
|
||||
|
||||
# Check free diskspace
|
||||
DIR=$(dirname "$DISK_FILE")
|
||||
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
|
||||
|
||||
if (( DATA_SIZE > SPACE )); then
|
||||
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
||||
error "Not enough free space to create a $DISK_DESC of $DISK_SPACE in $DIR, it has only $SPACE_GB GB available..."
|
||||
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 76
|
||||
fi
|
||||
fi
|
||||
|
||||
html "Creating a $DISK_DESC image..."
|
||||
info "Creating a $DISK_SPACE $DISK_TYPE $DISK_DESC image in $DISK_FMT format..."
|
||||
|
||||
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
|
||||
|
||||
case "${DISK_FMT,,}" in
|
||||
raw)
|
||||
|
||||
if isCow "$FS"; then
|
||||
if ! touch "$DISK_FILE"; then
|
||||
error "$FAIL" && exit 77
|
||||
fi
|
||||
{ chattr +C "$DISK_FILE"; } || :
|
||||
fi
|
||||
|
||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||
|
||||
# Create an empty file
|
||||
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
||||
rm -f "$DISK_FILE"
|
||||
error "$FAIL" && exit 77
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
# Create an empty file
|
||||
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
|
||||
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
||||
rm -f "$DISK_FILE"
|
||||
error "$FAIL" && exit 77
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
;;
|
||||
qcow2)
|
||||
|
||||
local DISK_PARAM="$DISK_ALLOC"
|
||||
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
|
||||
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
|
||||
|
||||
if ! qemu-img create -f "$DISK_FMT" -o "$DISK_PARAM" -- "$DISK_FILE" "$DATA_SIZE" ; then
|
||||
rm -f "$DISK_FILE"
|
||||
error "$FAIL" && exit 70
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if isCow "$FS"; then
|
||||
FA=$(lsattr "$DISK_FILE")
|
||||
if [[ "$FA" != *"C"* ]]; then
|
||||
error "Failed to disable COW for $DISK_DESC image $DISK_FILE on ${FS^^} filesystem (returned $FA)"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
resizeDisk() {
|
||||
local DISK_FILE=$1
|
||||
local DISK_SPACE=$2
|
||||
local DISK_DESC=$3
|
||||
local DISK_FMT=$4
|
||||
local FS=$5
|
||||
local CUR_SIZE DATA_SIZE DIR SPACE
|
||||
|
||||
CUR_SIZE=$(getSize "$DISK_FILE")
|
||||
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
|
||||
local REQ=$((DATA_SIZE-CUR_SIZE))
|
||||
(( REQ < 1 )) && error "Shrinking disks is not supported yet, please increase ${DISK_DESC^^}_SIZE." && exit 71
|
||||
|
||||
if [[ "$ALLOCATE" != [Nn]* ]]; then
|
||||
|
||||
# Check free diskspace
|
||||
DIR=$(dirname "$DISK_FILE")
|
||||
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
|
||||
|
||||
if (( REQ > SPACE )); then
|
||||
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
||||
error "Not enough free space to resize $DISK_DESC to $DISK_SPACE in $DIR, it has only $SPACE_GB GB available.."
|
||||
error "Please specify a smaller ${DISK_DESC^^}_SIZE or disable preallocation by setting ALLOCATE=N." && exit 74
|
||||
fi
|
||||
fi
|
||||
|
||||
local GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
|
||||
MSG="Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
|
||||
info "$MSG" && html "$MSG"
|
||||
|
||||
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
|
||||
|
||||
case "${DISK_FMT,,}" in
|
||||
raw)
|
||||
|
||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||
|
||||
# Resize file by changing its length
|
||||
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
||||
error "$FAIL" && exit 75
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
# Resize file by allocating more space
|
||||
if ! fallocate -l "$DATA_SIZE" "$DISK_FILE"; then
|
||||
if ! truncate -s "$DATA_SIZE" "$DISK_FILE"; then
|
||||
error "$FAIL" && exit 75
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
;;
|
||||
qcow2)
|
||||
|
||||
if ! qemu-img resize -f "$DISK_FMT" "--$DISK_ALLOC" "$DISK_FILE" "$DATA_SIZE" ; then
|
||||
error "$FAIL" && exit 72
|
||||
fi
|
||||
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
convertDisk() {
|
||||
local SOURCE_FILE=$1
|
||||
local SOURCE_FMT=$2
|
||||
local DST_FILE=$3
|
||||
local DST_FMT=$4
|
||||
local DISK_BASE=$5
|
||||
local DISK_DESC=$6
|
||||
local FS=$7
|
||||
|
||||
[ -f "$DST_FILE" ] && error "Conversion failed, destination file $DST_FILE already exists?" && exit 79
|
||||
[ ! -f "$SOURCE_FILE" ] && error "Conversion failed, source file $SOURCE_FILE does not exists?" && exit 79
|
||||
|
||||
local TMP_FILE="$DISK_BASE.tmp"
|
||||
rm -f "$TMP_FILE"
|
||||
|
||||
if [[ "$ALLOCATE" != [Nn]* ]]; then
|
||||
|
||||
local DIR CUR_SIZE SPACE
|
||||
|
||||
# Check free diskspace
|
||||
DIR=$(dirname "$TMP_FILE")
|
||||
CUR_SIZE=$(getSize "$SOURCE_FILE")
|
||||
SPACE=$(df --output=avail -B 1 "$DIR" | tail -n 1)
|
||||
|
||||
if (( CUR_SIZE > SPACE )); then
|
||||
local SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
|
||||
error "Not enough free space to convert $DISK_DESC to $DST_FMT in $DIR, it has only $SPACE_GB GB available..."
|
||||
error "Please free up some disk space or disable preallocation by setting ALLOCATE=N." && exit 76
|
||||
fi
|
||||
fi
|
||||
|
||||
html "Converting $DISK_DESC to $DST_FMT..."
|
||||
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
|
||||
|
||||
local CONV_FLAGS="-p"
|
||||
local DISK_PARAM="$DISK_ALLOC"
|
||||
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
|
||||
|
||||
if [[ "$DST_FMT" != "raw" ]]; then
|
||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||
CONV_FLAGS="$CONV_FLAGS -c"
|
||||
fi
|
||||
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
|
||||
rm -f "$TMP_FILE"
|
||||
error "Failed to convert $DISK_TYPE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
|
||||
fi
|
||||
|
||||
if [[ "$DST_FMT" == "raw" ]]; then
|
||||
if [[ "$ALLOCATE" != [Nn]* ]]; then
|
||||
# Work around qemu-img bug
|
||||
CUR_SIZE=$(stat -c%s "$TMP_FILE")
|
||||
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE"; then
|
||||
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f "$SOURCE_FILE"
|
||||
mv "$TMP_FILE" "$DST_FILE"
|
||||
|
||||
if isCow "$FS"; then
|
||||
FA=$(lsattr "$DST_FILE")
|
||||
if [[ "$FA" != *"C"* ]]; then
|
||||
error "Failed to disable COW for $DISK_DESC image $DST_FILE on ${FS^^} filesystem (returned $FA)"
|
||||
fi
|
||||
fi
|
||||
|
||||
html "Conversion of $DISK_DESC completed..."
|
||||
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
checkFS () {
|
||||
local FS=$1
|
||||
local DISK_FILE=$2
|
||||
local DISK_DESC=$3
|
||||
local DIR FA
|
||||
|
||||
DIR=$(dirname "$DISK_FILE")
|
||||
[ ! -d "$DIR" ] && return 0
|
||||
|
||||
if [[ "${FS,,}" == "overlay"* ]]; then
|
||||
info "Warning: the filesystem of $DIR is OverlayFS, this usually means it was binded to an invalid path!"
|
||||
fi
|
||||
|
||||
if [[ "${FS,,}" == "fuse"* ]]; then
|
||||
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
|
||||
fi
|
||||
|
||||
if isCow "$FS"; then
|
||||
if [ -f "$DISK_FILE" ]; then
|
||||
FA=$(lsattr "$DISK_FILE")
|
||||
if [[ "$FA" != *"C"* ]]; then
|
||||
info "Warning: COW (copy on write) is not disabled for $DISK_DESC image file $DISK_FILE, this is recommended on ${FS^^} filesystems!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
addDisk () {
|
||||
local DISK_ID=$1
|
||||
local DISK_BASE=$2
|
||||
local DISK_EXT=$3
|
||||
local DISK_DESC=$4
|
||||
local DISK_SPACE=$5
|
||||
local DISK_INDEX=$6
|
||||
local DISK_ADDRESS=$7
|
||||
local DISK_FMT=$8
|
||||
local DISK_FILE="$DISK_BASE.$DISK_EXT"
|
||||
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
|
||||
|
||||
DIR=$(dirname "$DISK_FILE")
|
||||
[ ! -d "$DIR" ] && return 0
|
||||
|
||||
[ -z "$DISK_SPACE" ] && DISK_SPACE="16G"
|
||||
DISK_SPACE=$(echo "${DISK_SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
|
||||
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
|
||||
|
||||
if (( DATA_SIZE < 1 )); then
|
||||
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
|
||||
fi
|
||||
|
||||
FS=$(stat -f -c %T "$DIR")
|
||||
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
|
||||
|
||||
if ! [ -f "$DISK_FILE" ] ; then
|
||||
|
||||
if [[ "${DISK_FMT,,}" != "raw" ]]; then
|
||||
PREV_FMT="raw"
|
||||
else
|
||||
PREV_FMT="qcow2"
|
||||
fi
|
||||
PREV_EXT=$(fmt2ext "$PREV_FMT")
|
||||
|
||||
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then
|
||||
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$DISK_FILE" ]; then
|
||||
|
||||
CUR_SIZE=$(getSize "$DISK_FILE")
|
||||
|
||||
if (( DATA_SIZE > CUR_SIZE )); then
|
||||
resizeDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
createDisk "$DISK_FILE" "$DISK_SPACE" "$DISK_DESC" "$DISK_FMT" "$FS" || exit $?
|
||||
|
||||
fi
|
||||
|
||||
DISK_OPTS="$DISK_OPTS \
|
||||
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
||||
-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
addDevice () {
|
||||
|
||||
local DISK_ID=$1
|
||||
local DISK_DEV=$2
|
||||
local DISK_DESC=$3
|
||||
local DISK_INDEX=$4
|
||||
local DISK_ADDRESS=$5
|
||||
|
||||
[ -z "$DISK_DEV" ] && return 0
|
||||
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
|
||||
|
||||
DISK_OPTS="$DISK_OPTS \
|
||||
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
|
||||
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
|
||||
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
html "Initializing disks..."
|
||||
|
||||
DISK1_FILE="$STORAGE/data"
|
||||
DISK2_FILE="/storage2/data2"
|
||||
DISK3_FILE="/storage3/data3"
|
||||
DISK4_FILE="/storage4/data4"
|
||||
|
||||
if [ -z "$DISK_FMT" ]; then
|
||||
if [ -f "$DISK1_FILE.qcow2" ]; then
|
||||
DISK_FMT="qcow2"
|
||||
else
|
||||
DISK_FMT="raw"
|
||||
fi
|
||||
fi
|
||||
|
||||
DISK_EXT=$(fmt2ext "$DISK_FMT")
|
||||
|
||||
if [ -z "$ALLOCATE" ]; then
|
||||
ALLOCATE="N"
|
||||
fi
|
||||
|
||||
if [[ "$ALLOCATE" == [Nn]* ]]; then
|
||||
DISK_TYPE="growable"
|
||||
DISK_ALLOC="preallocation=off"
|
||||
else
|
||||
DISK_TYPE="preallocated"
|
||||
DISK_ALLOC="preallocation=falloc"
|
||||
fi
|
||||
|
||||
: "${DISK2_SIZE:=""}"
|
||||
: "${DISK3_SIZE:=""}"
|
||||
: "${DISK4_SIZE:=""}"
|
||||
|
||||
: "${DEVICE:=""}" # Docker variables to passthrough a block device, like /dev/vdc1.
|
||||
: "${DEVICE2:=""}"
|
||||
: "${DEVICE3:=""}"
|
||||
: "${DEVICE4:=""}"
|
||||
|
||||
if [ -n "$DEVICE" ]; then
|
||||
addDevice "userdata" "$DEVICE" "device" "3" "0xa" || exit $?
|
||||
else
|
||||
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xa" "$DISK_FMT" || exit $?
|
||||
fi
|
||||
|
||||
if [ -n "$DEVICE2" ]; then
|
||||
addDevice "userdata2" "$DEVICE2" "device2" "4" "0xb" || exit $?
|
||||
else
|
||||
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xb" "$DISK_FMT" || exit $?
|
||||
fi
|
||||
|
||||
if [ -n "$DEVICE3" ]; then
|
||||
addDevice "userdata3" "$DEVICE3" "device3" "5" "0xc" || exit $?
|
||||
else
|
||||
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xc" "$DISK_FMT" || exit $?
|
||||
fi
|
||||
|
||||
if [ -n "$DEVICE4" ]; then
|
||||
addDevice "userdata4" "$DEVICE4" "device4" "6" "0xd" || exit $?
|
||||
else
|
||||
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xd" "$DISK_FMT" || exit $?
|
||||
fi
|
||||
|
||||
html "Initialized disks successfully..."
|
||||
return 0
|
||||
@@ -1,53 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
|
||||
: "${GPU:="N"}" # GPU passthrough
|
||||
: "${VGA:="virtio"}" # VGA adaptor
|
||||
: "${DISPLAY:="web"}" # Display type
|
||||
|
||||
case "${DISPLAY,,}" in
|
||||
vnc)
|
||||
DISPLAY_OPTS="-display vnc=:0 -vga $VGA"
|
||||
;;
|
||||
web)
|
||||
DISPLAY_OPTS="-display vnc=:0,websocket=5700 -vga $VGA"
|
||||
;;
|
||||
none)
|
||||
DISPLAY_OPTS="-display none -vga none"
|
||||
;;
|
||||
*)
|
||||
DISPLAY_OPTS="-display $DISPLAY -vga $VGA"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
[[ "${VGA,,}" == "virtio" ]] && VGA="virtio-vga-gl"
|
||||
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128"
|
||||
DISPLAY_OPTS="$DISPLAY_OPTS -vga none -device $VGA"
|
||||
|
||||
[[ "${DISPLAY,,}" == "vnc" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0"
|
||||
[[ "${DISPLAY,,}" == "web" ]] && DISPLAY_OPTS="$DISPLAY_OPTS -vnc :0,websocket=5700"
|
||||
|
||||
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
|
||||
|
||||
if [ ! -c /dev/dri/card0 ]; then
|
||||
if mknod /dev/dri/card0 c 226 0; then
|
||||
chmod 666 /dev/dri/card0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -c /dev/dri/renderD128 ]; then
|
||||
if mknod /dev/dri/renderD128 c 226 128; then
|
||||
chmod 666 /dev/dri/renderD128
|
||||
fi
|
||||
fi
|
||||
|
||||
addPackage "xserver-xorg-video-intel" "Intel GPU drivers"
|
||||
addPackage "qemu-system-modules-opengl" "OpenGL module"
|
||||
|
||||
return 0
|
||||
+94
-11
@@ -1,23 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Based on https://github.com/qemus/qemu-docker
|
||||
set -Eeuo pipefail
|
||||
|
||||
APP="QEMU"
|
||||
SUPPORT="https://github.com/qemus/qemu-docker"
|
||||
|
||||
APP="OpenWrt"
|
||||
SUPPORT="albrechtloh@gmx.de"
|
||||
|
||||
attach_eth_if () {
|
||||
HOST_IF=$1
|
||||
CONTAINER_IF=$2
|
||||
QEMU_IF=$3
|
||||
# Privilige=true and pid=host mode necessary
|
||||
# Sources
|
||||
# * https://serverfault.com/questions/688483/assign-physical-interface-to-docker-exclusively
|
||||
# * https://medium.com/lucjuggery/a-container-to-access-the-shell-of-the-host-2c7c227c64e9
|
||||
# * https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#
|
||||
|
||||
info "Attaching physical Ethernet interface $HOST_IF into container with the name $CONTAINER_IF ..."
|
||||
PID_CONTAINTER=$(nsenter --target 1 --uts --net --ipc --mount docker inspect -f '{{.State.Pid}}' $(cat /etc/hostname))
|
||||
nsenter --target 1 --uts --net --ipc --mount mkdir -p /var/run/netns
|
||||
nsenter --target 1 --uts --net --ipc --mount ln -s /proc/$PID_CONTAINTER/ns/net /var/run/netns/$PID_CONTAINTER
|
||||
nsenter --target 1 --uts --net --ipc --mount ip link set $HOST_IF netns $PID_CONTAINTER name $CONTAINER_IF
|
||||
nsenter --target 1 --uts --net --ipc --mount ip netns exec $PID_CONTAINTER ip link set $CONTAINER_IF up
|
||||
nsenter --target 1 --uts --net --ipc --mount rm /var/run/netns/$PID_CONTAINTER
|
||||
|
||||
#ip link add link $CONTAINER_IF name $QEMU_IF type ipvlan mode l2
|
||||
#ip link add link $CONTAINER_IF name $QEMU_IF type macvtap mode bridge
|
||||
ip link add link $CONTAINER_IF name $QEMU_IF type macvtap mode passthru
|
||||
ip link set $QEMU_IF up
|
||||
}
|
||||
|
||||
cd /run
|
||||
|
||||
. reset.sh # Initialize system
|
||||
. install.sh # Get bootdisk
|
||||
. disk.sh # Initialize disks
|
||||
. display.sh # Initialize graphics
|
||||
. network.sh # Initialize network
|
||||
. boot.sh # Configure boot
|
||||
. proc.sh # Initialize processor
|
||||
. config.sh # Configure arguments
|
||||
# Initialize system
|
||||
. reset.sh
|
||||
|
||||
trap - ERR
|
||||
|
||||
# Check if rootfs is in volume
|
||||
FILE=/storage/rootfs.img
|
||||
if [ -f "$FILE" ]; then
|
||||
info "$FILE exists. Nothing to do."
|
||||
else
|
||||
info "$FILE does not exist. Copying image to storage ..."
|
||||
cp /var/vm/rootfs.img.gz /storage/rootfs.img.gz
|
||||
gzip -d /storage/rootfs.img.gz
|
||||
fi
|
||||
|
||||
|
||||
info "Activating web VNC ..."
|
||||
[ ! -f "$INFO" ] && error "File $INFO not found?!"
|
||||
rm -f "$INFO"
|
||||
[ ! -f "$PAGE" ] && error "File $PAGE not found?!"
|
||||
rm -f "$PAGE"
|
||||
|
||||
|
||||
info "Checking for KVM ..."
|
||||
KVM_ERR=""
|
||||
CPU="-cpu cortex-a53"
|
||||
if [ ! -e /dev/kvm ]; then
|
||||
KVM_ERR="(device file missing)"
|
||||
else
|
||||
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
|
||||
KVM_ERR="(no write access)"
|
||||
else
|
||||
CPU="--enable-kvm -cpu host"
|
||||
info "KVM detected"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$KVM_ERR" ]; then
|
||||
KVM="N"
|
||||
warning "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
|
||||
fi
|
||||
|
||||
# Attach physical PHY to container
|
||||
# HOST_WAN_IF="enx00e04c0407a6" # WAN
|
||||
# HOST_LAN_IF="enx00e04d68033f" # LAN
|
||||
HOST_WAN_IF=$WAN_IF
|
||||
HOST_LAN_IF=$LAN_IF
|
||||
attach_eth_if $HOST_WAN_IF $HOST_WAN_IF qwan0
|
||||
attach_eth_if $HOST_LAN_IF $HOST_LAN_IF qlan0
|
||||
|
||||
|
||||
info "Booting image using $VERS..."
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
||||
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
|
||||
exec qemu-system-aarch64 -M virt \
|
||||
-m 512 \
|
||||
-nodefaults \
|
||||
$CPU -smp 2 \
|
||||
-bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \
|
||||
-display vnc=:0,websocket=5700 \
|
||||
-vga none -device ramfb \
|
||||
-kernel /var/vm/kernel.bin -append "root=fe00 console=tty0" \
|
||||
-blockdev driver=raw,node-name=hd0,cache.direct=on,file.driver=file,file.filename=/storage/rootfs.img \
|
||||
-device virtio-blk-pci,drive=hd0 \
|
||||
-device qemu-xhci -device usb-kbd \
|
||||
-device virtio-net-pci,netdev=hostnet0 \
|
||||
-netdev tap,fd=30,id=hostnet0 30<>/dev/tap$(cat /sys/class/net/qlan0/ifindex) \
|
||||
-device virtio-net-pci,netdev=hostnet1 \
|
||||
-netdev tap,fd=31,id=hostnet1 31<>/dev/tap$(cat /sys/class/net/qwan0/ifindex)
|
||||
|
||||
#- device virtio-net,netdev=qlan1 -netdev user,id=qlan1,net=192.168.1.0/24,hostfwd=tcp::8000-192.168.1.1:80 \
|
||||
# -blockdev driver=raw,node-name=hd0,cache.direct=on,file.driver=file,file.filename=/var/vm/openwrt-armsr-armv8-generic-ext4-combined.img \
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Check if running with interactive TTY or redirected to docker log
|
||||
if [ -t 1 ]; then
|
||||
PROGRESS="--progress=bar:noscroll"
|
||||
else
|
||||
PROGRESS="--progress=dot:giga"
|
||||
fi
|
||||
|
||||
BASE="boot.img"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="boot.iso"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="Boot.img"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="Boot.iso"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="boot.IMG"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="boot.ISO"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="BOOT.IMG"
|
||||
[ ! -f "$STORAGE/$BASE" ] && BASE="BOOT.ISO"
|
||||
|
||||
[ -f "$STORAGE/$BASE" ] && return 0
|
||||
|
||||
if [ -z "$BOOT" ]; then
|
||||
error "No boot disk specified, set BOOT= to the URL of an ISO file." && exit 64
|
||||
fi
|
||||
|
||||
BASE=$(basename "$BOOT")
|
||||
[ -f "$STORAGE/$BASE" ] && return 0
|
||||
|
||||
BASE=$(basename "${BOOT%%\?*}")
|
||||
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
|
||||
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
|
||||
[ -f "$STORAGE/$BASE" ] && return 0
|
||||
|
||||
TMP="$STORAGE/${BASE%.*}.tmp"
|
||||
rm -f "$TMP"
|
||||
|
||||
MSG="Downloading $BASE as boot image..."
|
||||
info "$MSG" && html "$MSG"
|
||||
|
||||
{ wget "$BOOT" -O "$TMP" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
|
||||
|
||||
(( rc != 0 )) && error "Failed to download $BOOT , reason: $rc" && exit 60
|
||||
[ ! -f "$TMP" ] && error "Failed to download $BOOT" && exit 61
|
||||
|
||||
SIZE=$(stat -c%s "$TMP")
|
||||
|
||||
if ((SIZE<100000)); then
|
||||
error "Invalid ISO file: Size is smaller than 100 KB" && exit 62
|
||||
fi
|
||||
|
||||
mv -f "$TMP" "$STORAGE/$BASE"
|
||||
|
||||
html "Download finished successfully..."
|
||||
return 0
|
||||
-295
@@ -1,295 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
|
||||
: "${DHCP:="N"}"
|
||||
: "${HOST_PORTS:=""}"
|
||||
: "${MAC:="82:cf:d0:5e:57:66"}"
|
||||
|
||||
: "${VM_NET_DEV:=""}"
|
||||
: "${VM_NET_TAP:="qemu"}"
|
||||
: "${VM_NET_MAC:="$MAC"}"
|
||||
: "${VM_NET_HOST:="QEMU"}"
|
||||
|
||||
: "${DNSMASQ_OPTS:=""}"
|
||||
: "${DNSMASQ:="/usr/sbin/dnsmasq"}"
|
||||
: "${DNSMASQ_CONF_DIR:="/etc/dnsmasq.d"}"
|
||||
|
||||
ADD_ERR="Please add the following setting to your container:"
|
||||
|
||||
# ######################################
|
||||
# Functions
|
||||
# ######################################
|
||||
|
||||
configureDHCP() {
|
||||
|
||||
# Create a macvtap network for the VM guest
|
||||
|
||||
{ ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || :
|
||||
|
||||
if (( rc != 0 )); then
|
||||
error "Cannot create macvtap interface. Please make sure the network type is 'macvlan' and not 'ipvlan',"
|
||||
error "and that the NET_ADMIN capability has been added to the container: --cap-add NET_ADMIN" && exit 16
|
||||
fi
|
||||
|
||||
while ! ip link set "$VM_NET_TAP" up; do
|
||||
info "Waiting for address to become available..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
local TAP_NR TAP_PATH MAJOR MINOR
|
||||
TAP_NR=$(</sys/class/net/"$VM_NET_TAP"/ifindex)
|
||||
TAP_PATH="/dev/tap${TAP_NR}"
|
||||
|
||||
# Create dev file (there is no udev in container: need to be done manually)
|
||||
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
|
||||
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && exit 18
|
||||
|
||||
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
|
||||
|
||||
if [[ ! -e "$TAP_PATH" ]]; then
|
||||
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
|
||||
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && exit 20
|
||||
fi
|
||||
|
||||
{ exec 30>>"$TAP_PATH"; rc=$?; } 2>/dev/null || :
|
||||
|
||||
if (( rc != 0 )); then
|
||||
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && exit 21
|
||||
fi
|
||||
|
||||
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
||||
|
||||
if (( rc != 0 )); then
|
||||
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && exit 22
|
||||
fi
|
||||
|
||||
NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
configureDNS() {
|
||||
|
||||
# dnsmasq configuration:
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
|
||||
|
||||
# Create lease file for faster resolve
|
||||
echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:$VM_NET_MAC" > /var/lib/misc/dnsmasq.leases
|
||||
chmod 644 /var/lib/misc/dnsmasq.leases
|
||||
|
||||
# Set DNS server and gateway
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
|
||||
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
||||
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
|
||||
error "Failed to start dnsmasq, reason: $?" && exit 29
|
||||
fi
|
||||
{ set +x; } 2>/dev/null
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
getPorts() {
|
||||
|
||||
local list=$1
|
||||
local vnc="5900"
|
||||
local web="8006"
|
||||
|
||||
[ -z "$list" ] && list="$web" || list="$list,$web"
|
||||
|
||||
if [[ "${DISPLAY,,}" == "vnc" ]] || [[ "${DISPLAY,,}" == "web" ]]; then
|
||||
[ -z "$list" ] && list="$vnc" || list="$list,$vnc"
|
||||
fi
|
||||
|
||||
[ -z "$list" ] && return 0
|
||||
|
||||
if [[ "$list" != *","* ]]; then
|
||||
echo " ! --dport $list"
|
||||
else
|
||||
echo " -m multiport ! --dports $list"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
configureNAT() {
|
||||
|
||||
# Create the necessary file structure for /dev/net/tun
|
||||
if [ ! -c /dev/net/tun ]; then
|
||||
[ ! -d /dev/net ] && mkdir -m 755 /dev/net
|
||||
if mknod /dev/net/tun c 10 200; then
|
||||
chmod 666 /dev/net/tun
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -c /dev/net/tun ]; then
|
||||
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25
|
||||
fi
|
||||
|
||||
# Check port forwarding flag
|
||||
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
|
||||
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || :
|
||||
if (( rc != 0 )); then
|
||||
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create a bridge with a static IP for the VM guest
|
||||
|
||||
VM_NET_IP='20.20.20.21'
|
||||
[[ "$DEBUG" == [Yy1]* ]] && set -x
|
||||
|
||||
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
|
||||
|
||||
if (( rc != 0 )); then
|
||||
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && exit 23
|
||||
fi
|
||||
|
||||
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
|
||||
|
||||
while ! ip link set dockerbridge up; do
|
||||
info "Waiting for address to become available..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# QEMU Works with taps, set tap to the bridge created
|
||||
ip tuntap add dev "$VM_NET_TAP" mode tap
|
||||
|
||||
while ! ip link set "$VM_NET_TAP" up promisc on; do
|
||||
info "Waiting for tap to become available..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
ip link set dev "$VM_NET_TAP" master dockerbridge
|
||||
|
||||
# Add internet connection to the VM
|
||||
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
|
||||
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
|
||||
|
||||
exclude=$(getPorts "$HOST_PORTS")
|
||||
|
||||
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE
|
||||
# shellcheck disable=SC2086
|
||||
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"
|
||||
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
|
||||
|
||||
if (( KERNEL > 4 )); then
|
||||
# Hack for guest VMs complaining about "bad udp checksums in 5 packets"
|
||||
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true
|
||||
fi
|
||||
|
||||
{ set +x; } 2>/dev/null
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo
|
||||
|
||||
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
|
||||
|
||||
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
|
||||
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40"
|
||||
|
||||
configureDNS
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
closeNetwork() {
|
||||
|
||||
# Shutdown nginx
|
||||
nginx -s stop 2> /dev/null
|
||||
fWait "nginx"
|
||||
|
||||
exec 30<&- || true
|
||||
exec 40<&- || true
|
||||
|
||||
if [[ "$DHCP" == [Yy1]* ]]; then
|
||||
|
||||
ip link set "$VM_NET_TAP" down || true
|
||||
ip link delete "$VM_NET_TAP" || true
|
||||
|
||||
else
|
||||
|
||||
local pid="/var/run/dnsmasq.pid"
|
||||
[ -f "$pid" ] && pKill "$(<"$pid")"
|
||||
|
||||
ip link set "$VM_NET_TAP" down promisc off || true
|
||||
ip link delete "$VM_NET_TAP" || true
|
||||
|
||||
ip link set dockerbridge down || true
|
||||
ip link delete dockerbridge || true
|
||||
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
getInfo() {
|
||||
|
||||
if [ -z "$VM_NET_DEV" ]; then
|
||||
# Automaticly detect the default network interface
|
||||
VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
|
||||
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
|
||||
fi
|
||||
|
||||
if [ ! -d "/sys/class/net/$VM_NET_DEV" ]; then
|
||||
error "Network interface '$VM_NET_DEV' does not exist inside the container!"
|
||||
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
|
||||
fi
|
||||
|
||||
VM_NET_MAC="${VM_NET_MAC//-/:}"
|
||||
if [[ ${#VM_NET_MAC} == 12 ]]; then
|
||||
m="$VM_NET_MAC"
|
||||
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
|
||||
fi
|
||||
|
||||
if [[ ${#VM_NET_MAC} != 17 ]]; then
|
||||
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
|
||||
fi
|
||||
|
||||
GATEWAY=$(ip r | grep default | awk '{print $3}')
|
||||
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ######################################
|
||||
# Configure Network
|
||||
# ######################################
|
||||
|
||||
if [ ! -c /dev/vhost-net ]; then
|
||||
if mknod /dev/vhost-net c 10 238; then
|
||||
chmod 660 /dev/vhost-net
|
||||
fi
|
||||
fi
|
||||
|
||||
getInfo
|
||||
html "Initializing network..."
|
||||
|
||||
if [[ "$DEBUG" == [Yy1]* ]]; then
|
||||
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo
|
||||
fi
|
||||
|
||||
if [[ "$DHCP" == [Yy1]* ]]; then
|
||||
|
||||
if [[ "$GATEWAY" == "172."* ]]; then
|
||||
if [[ "$DEBUG" != [Yy1]* ]]; then
|
||||
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
|
||||
fi
|
||||
fi
|
||||
|
||||
# Configuration for DHCP IP
|
||||
configureDHCP
|
||||
|
||||
else
|
||||
|
||||
# Configuration for static IP
|
||||
configureNAT
|
||||
|
||||
fi
|
||||
|
||||
NET_OPTS="$NET_OPTS -device virtio-net-pci,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0"
|
||||
|
||||
html "Initialized network successfully..."
|
||||
return 0
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Docker environment variables
|
||||
|
||||
: "${KVM:="Y"}"
|
||||
: "${CPU_FLAGS:=""}"
|
||||
: "${CPU_MODEL:="host"}"
|
||||
|
||||
[ "$ARCH" != "amd64" ] && KVM="N"
|
||||
|
||||
if [[ "$KVM" != [Nn]* ]]; then
|
||||
|
||||
KVM_ERR=""
|
||||
|
||||
if [ ! -e /dev/kvm ]; then
|
||||
KVM_ERR="(device file missing)"
|
||||
else
|
||||
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
|
||||
KVM_ERR="(no write access)"
|
||||
else
|
||||
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
|
||||
KVM_ERR="(vmx/svm disabled)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$KVM_ERR" ]; then
|
||||
KVM="N"
|
||||
error "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
|
||||
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
|
||||
[[ "$DEBUG" != [Yy1]* ]] && exit 88
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [[ "$KVM" != [Nn]* ]]; then
|
||||
|
||||
CPU_FEATURES="kvm=on"
|
||||
KVM_OPTS=",accel=kvm -enable-kvm"
|
||||
|
||||
if [[ "${BOOT_MODE,,}" == "windows" ]] || [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
||||
|
||||
CPU_FEATURES="kvm=on,+hypervisor,+invtsc,l3-cache=on,migratable=no,hv_passthrough"
|
||||
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
KVM_OPTS=""
|
||||
CPU_FEATURES="+ssse3,+sse4.1,+sse4.2"
|
||||
|
||||
if [[ "${CPU_MODEL,,}" == "host"* ]]; then
|
||||
|
||||
if [[ "$ARCH" == "amd64" ]]; then
|
||||
CPU_MODEL="max"
|
||||
else
|
||||
CPU_MODEL="qemu64"
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CPU_FLAGS" ]; then
|
||||
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
|
||||
else
|
||||
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
|
||||
fi
|
||||
|
||||
return 0
|
||||
+6
-1
@@ -17,6 +17,7 @@ echo
|
||||
# Docker environment variables
|
||||
|
||||
: "${BOOT:=""}" # URL of the ISO file
|
||||
: "${KERNELIMG:=""}" # URL of the ISO file
|
||||
: "${DEBUG:="N"}" # Disable debugging
|
||||
: "${ALLOCATE:=""}" # Preallocate diskspace
|
||||
: "${ARGUMENTS:=""}" # Extra QEMU parameters
|
||||
@@ -24,6 +25,10 @@ echo
|
||||
: "${RAM_SIZE:="1G"}" # Maximum RAM amount
|
||||
: "${DISK_SIZE:="16G"}" # Initial data disk size
|
||||
: "${BOOT_INDEX:="10"}" # Boot index of CD drive
|
||||
: "${DISPLAY:="web"}" # Display type
|
||||
: "${KVM:="Y"}"
|
||||
: "${CPU_FLAGS:=""}"
|
||||
: "${CPU_MODEL:="host"}"
|
||||
|
||||
# Helper variables
|
||||
|
||||
@@ -37,7 +42,7 @@ FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
|
||||
KERNEL=$(uname -r | cut -b 1)
|
||||
MINOR=$(uname -r | cut -d '.' -f2)
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
|
||||
VERS=$(qemu-system-aarch64 --version | head -n 1 | cut -d '(' -f 1)
|
||||
|
||||
# Check system
|
||||
|
||||
|
||||
Reference in New Issue
Block a user